diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/extractor/ExtractorBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/block/extractor/ExtractorBlockEntity.kt index d38b411..8a52813 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/extractor/ExtractorBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/extractor/ExtractorBlockEntity.kt @@ -39,7 +39,7 @@ class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR), private var inventory: FixedItemInv? = null override val pendingInsertions = mutableListOf() - override val dispatchStackTimeout = 40L + override val dispatchStackTimeout = 1L override val controller = ActivationController(SLEEP_TIME, this) fun updateInventory() { diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/netinterface/InterfaceBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/block/netinterface/InterfaceBlockEntity.kt index 33abbfd..54daefd 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/netinterface/InterfaceBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/netinterface/InterfaceBlockEntity.kt @@ -33,6 +33,7 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), get() = cachedState[FaceDeviceBlock.FACING] override var providerPriority = 0 + override var receiverPriority = 0 // todo: should this be a weak ref? private var inventory: GroupedItemInv? = null @@ -119,10 +120,12 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), override fun writeDeviceConfiguration(tag: CompoundTag) { tag.putInt("ProviderPriority", providerPriority) + tag.putInt("ReceiverPriority", receiverPriority) } override fun loadDeviceConfiguration(tag: CompoundTag) { providerPriority = tag.getInt("ProviderPriority") + receiverPriority = tag.getInt("ReceiverPriority") } } diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalBlockEntity.kt index 09969a3..35396db 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/terminal/TerminalBlockEntity.kt @@ -41,10 +41,10 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), NetworkStackDispatcher { companion object { - // the locate request timeout is only 1 tick because that's long enough to hear from every device on the network + // the locate/insertion timeouts are only 1 tick because that's long enough to hear from every device on the network // in a degraded state (when there's latency in the network), not handling interface priorities correctly is acceptable val LOCATE_REQUEST_TIMEOUT: Long = 1 // ticks - val INSERTION_TIMEOUT: Long = 40 + val INSERTION_TIMEOUT: Long = 1 } private val inventoryCache = mutableMapOf() diff --git a/src/main/kotlin/net/shadowfacts/phycon/component/NetworkStackDispatcher.kt b/src/main/kotlin/net/shadowfacts/phycon/component/NetworkStackDispatcher.kt index 9c9ae3d..dbc61f8 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/component/NetworkStackDispatcher.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/component/NetworkStackDispatcher.kt @@ -44,8 +44,15 @@ interface NetworkStackDispatcher + // sort results first by receiver priority, and then by capacity + if (a.second.receiverPriority == b.second.receiverPriority) { + b.first - a.first + } else { + b.second.receiverPriority - a.second.receiverPriority + } + } // copy the insertion stack so subclasses that override this method can still see the originally dispatched stack after the super call val remaining = insertion.stack.copy() while (!remaining.isEmpty && sortedResults.isNotEmpty()) { @@ -70,7 +77,8 @@ interface NetworkStackDispatcher acc + amount } fun isFinishable(owner: NetworkStackDispatcher): Boolean { - return totalCapacity >= stack.count || owner.counter - timestamp >= owner.dispatchStackTimeout + // can't check totalCapacity >= stack.count because we need to wait for all responses to correctly sort by priority + return owner.counter - timestamp >= owner.dispatchStackTimeout } } } diff --git a/src/main/kotlin/net/shadowfacts/phycon/component/NetworkStackReceiver.kt b/src/main/kotlin/net/shadowfacts/phycon/component/NetworkStackReceiver.kt index a079314..c813a5a 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/component/NetworkStackReceiver.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/component/NetworkStackReceiver.kt @@ -1,9 +1,13 @@ package net.shadowfacts.phycon.component import net.shadowfacts.phycon.api.NetworkDevice +import net.shadowfacts.phycon.util.ClientConfigurableDevice /** * @author shadowfacts */ -interface NetworkStackReceiver: NetworkDevice { +interface NetworkStackReceiver: NetworkDevice, ClientConfigurableDevice { + + var receiverPriority: Int + } diff --git a/src/main/kotlin/net/shadowfacts/phycon/screen/console/DeviceConsoleScreen.kt b/src/main/kotlin/net/shadowfacts/phycon/screen/console/DeviceConsoleScreen.kt index 71d53df..3a7c0c4 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/screen/console/DeviceConsoleScreen.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/screen/console/DeviceConsoleScreen.kt @@ -17,6 +17,7 @@ import net.shadowfacts.phycon.block.miner.MinerBlockEntity import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity import net.shadowfacts.phycon.component.ActivationController import net.shadowfacts.phycon.component.NetworkStackProvider +import net.shadowfacts.phycon.component.NetworkStackReceiver import org.lwjgl.glfw.GLFW /** @@ -72,6 +73,13 @@ class DeviceConsoleScreen( device::canConfigureProviderPriority )) } + if (device is NetworkStackReceiver) { + tabs.add(TabViewController.SimpleTab( + Label("R").apply { textColor = Color.TEXT }, + TranslatableText("gui.phycon.console.receiver"), + ReceiverViewController(device), + )) + } tabController = TabViewController(tabs) diff --git a/src/main/kotlin/net/shadowfacts/phycon/screen/console/ReceiverViewController.kt b/src/main/kotlin/net/shadowfacts/phycon/screen/console/ReceiverViewController.kt new file mode 100644 index 0000000..84488a2 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/screen/console/ReceiverViewController.kt @@ -0,0 +1,57 @@ +package net.shadowfacts.phycon.screen.console + +import net.minecraft.block.entity.BlockEntity +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.NumberField +import net.shadowfacts.cacao.viewcontroller.ViewController +import net.shadowfacts.kiwidsl.dsl +import net.shadowfacts.phycon.component.NetworkStackReceiver +import net.shadowfacts.phycon.networking.C2SConfigureDevice + +/** + * @author shadowfacts + */ +class ReceiverViewController( + private val device: T +): ViewController() where T: BlockEntity, T: NetworkStackReceiver { + + override fun viewDidLoad() { + super.viewDidLoad() + + val label = Label(TranslatableText("gui.phycon.console.receiver.priority")).apply { + textColor = Color.TEXT + } + view.addSubview(label) + + val field = NumberField(device.receiverPriority) { + if (it.number != null) { + device.receiverPriority = it.number!! + MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device)) + } + } + view.addSubview(field) + + val desc = Label(TranslatableText("gui.phycon.console.receiver.priority_desc")).apply { + textColor = Color.TEXT + } + view.addSubview(desc) + + view.solver.dsl { + field.widthAnchor equalTo 100 + field.heightAnchor equalTo 20 + field.rightAnchor equalTo view.rightAnchor + field.topAnchor equalTo view.topAnchor + + label.centerYAnchor equalTo field.centerYAnchor + label.rightAnchor equalTo (field.leftAnchor - 4) + + desc.topAnchor equalTo (field.bottomAnchor + 4) + desc.leftAnchor equalTo view.leftAnchor + desc.rightAnchor equalTo view.rightAnchor + } + } + +} diff --git a/src/main/resources/assets/phycon/lang/en_us.json b/src/main/resources/assets/phycon/lang/en_us.json index d615151..0b4f3bb 100644 --- a/src/main/resources/assets/phycon/lang/en_us.json +++ b/src/main/resources/assets/phycon/lang/en_us.json @@ -24,6 +24,9 @@ "gui.phycon.console.provider": "Item Provider", "gui.phycon.console.provider.priority": "Provider Priority", "gui.phycon.console.provider.priority_desc": "When a device requests items from the network, it send requests to providers (e.g., interfaces) with higher priorities first. Priorities can be negative.", + "gui.phycon.console.receiver": "Item Receiver", + "gui.phycon.console.receiver.priority": "Receiver Priority", + "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.redstone_mode.high": "High", "gui.phycon.redstone_mode.low": "Low", "gui.phycon.redstone_mode.toggle": "Toggle",