Add network stack provider priorities
This commit is contained in:
parent
2d3ac4538d
commit
170e50755a
|
@ -10,7 +10,7 @@ class NumberField(
|
|||
|
||||
var number: Int?
|
||||
get() {
|
||||
return if (text.isEmpty()) {
|
||||
return if (isTextTemporarilyAllowed(text)) {
|
||||
null
|
||||
} else {
|
||||
try {
|
||||
|
@ -31,7 +31,7 @@ class NumberField(
|
|||
}
|
||||
|
||||
override fun validate(proposedText: String): Boolean {
|
||||
return proposedText.isEmpty() || try {
|
||||
return isTextTemporarilyAllowed(proposedText) || try {
|
||||
val value = Integer.parseInt(proposedText)
|
||||
validator?.invoke(value) ?: true
|
||||
} catch (e: NumberFormatException) {
|
||||
|
@ -39,4 +39,8 @@ class NumberField(
|
|||
}
|
||||
}
|
||||
|
||||
private fun isTextTemporarilyAllowed(s: String): Boolean {
|
||||
return s.isEmpty() || s == "-"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import alexiil.mc.lib.attributes.Simulation
|
|||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||
import alexiil.mc.lib.attributes.item.ItemInsertable
|
||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.util.math.Direction
|
||||
|
|
|
@ -44,6 +44,7 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||
override val dispatchStackTimeout = TerminalBlockEntity.INSERTION_TIMEOUT
|
||||
override val controller = ActivationController(40L, this)
|
||||
override var providerPriority = 0
|
||||
|
||||
var minerMode = MinerMode.ON_DEMAND
|
||||
|
||||
|
@ -151,6 +152,10 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
return minerMode == MinerMode.AUTOMATIC
|
||||
}
|
||||
|
||||
override fun canConfigureProviderPriority(): Boolean {
|
||||
return minerMode == MinerMode.ON_DEMAND
|
||||
}
|
||||
|
||||
override fun toCommonTag(tag: CompoundTag) {
|
||||
super.toCommonTag(tag)
|
||||
writeDeviceConfiguration(tag)
|
||||
|
@ -164,11 +169,13 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putString("MinerMode", minerMode.name)
|
||||
tag.putString("ActivationMode", controller.activationMode.name)
|
||||
tag.putInt("ProviderPriority", providerPriority)
|
||||
}
|
||||
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
minerMode = MinerMode.valueOf(tag.getString("MinerMode"))
|
||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||
providerPriority = tag.getInt("ProviderPriority")
|
||||
}
|
||||
|
||||
enum class MinerMode {
|
||||
|
|
|
@ -4,7 +4,9 @@ import alexiil.mc.lib.attributes.SearchOptions
|
|||
import alexiil.mc.lib.attributes.Simulation
|
||||
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
|
@ -15,6 +17,7 @@ import net.shadowfacts.phycon.component.NetworkStackProvider
|
|||
import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||
import net.shadowfacts.phycon.component.handleItemStack
|
||||
import net.shadowfacts.phycon.packet.*
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
|
@ -23,11 +26,14 @@ import kotlin.math.min
|
|||
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
||||
ItemStackPacketHandler,
|
||||
NetworkStackProvider,
|
||||
NetworkStackReceiver {
|
||||
NetworkStackReceiver,
|
||||
ClientConfigurableDevice {
|
||||
|
||||
private val facing: Direction
|
||||
get() = cachedState[FaceDeviceBlock.FACING]
|
||||
|
||||
override var providerPriority = 0
|
||||
|
||||
// todo: should this be a weak ref?
|
||||
private var inventory: GroupedItemInv? = null
|
||||
|
||||
|
@ -101,4 +107,22 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
|||
}
|
||||
}
|
||||
|
||||
override fun toCommonTag(tag: CompoundTag) {
|
||||
super.toCommonTag(tag)
|
||||
writeDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun fromCommonTag(tag: CompoundTag) {
|
||||
super.fromCommonTag(tag)
|
||||
loadDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putInt("ProviderPriority", providerPriority)
|
||||
}
|
||||
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
providerPriority = tag.getInt("ProviderPriority")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import alexiil.mc.lib.attributes.item.ItemStackCollections
|
|||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.inventory.Inventory
|
||||
|
@ -42,7 +41,9 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
|||
NetworkStackDispatcher<TerminalBlockEntity.PendingInsertion> {
|
||||
|
||||
companion object {
|
||||
val LOCATE_REQUEST_TIMEOUT: Long = 40 // ticks
|
||||
// the locate request timeout is 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
|
||||
}
|
||||
|
||||
|
@ -163,14 +164,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
|||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
if (counter % 20 == 0L) {
|
||||
if (!world!!.isClient) {
|
||||
finishPendingRequests()
|
||||
beginInsertions()
|
||||
finishTimedOutPendingInsertions()
|
||||
}
|
||||
if (!world!!.isClient) {
|
||||
finishPendingRequests()
|
||||
finishTimedOutPendingInsertions()
|
||||
}
|
||||
|
||||
if (observers > 0 && !world!!.isClient) {
|
||||
if (counter % 20 == 0L && !world!!.isClient) {
|
||||
beginInsertions()
|
||||
|
||||
if (observers > 0) {
|
||||
updateAndSync()
|
||||
}
|
||||
}
|
||||
|
@ -209,8 +211,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
|||
private fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
||||
pendingRequests.remove(request)
|
||||
|
||||
// todo: also sort results by interface priority
|
||||
val sortedResults = request.results.sortedByDescending { it.first }.toMutableList()
|
||||
val sortedResults = request.results.toMutableList()
|
||||
sortedResults.sortWith { a, b ->
|
||||
// sort results first by provider priority, and then by the count that it can provide
|
||||
if (a.second.providerPriority == b.second.providerPriority) {
|
||||
b.first - a.first
|
||||
} else {
|
||||
b.second.providerPriority - a.second.providerPriority
|
||||
}
|
||||
}
|
||||
var amountRequested = 0
|
||||
while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
|
||||
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
|
||||
|
@ -268,6 +277,8 @@ data class StackLocateRequest(
|
|||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||
|
||||
fun isFinishable(currentTimestamp: Long): Boolean {
|
||||
return totalResultAmount >= amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
|
||||
// we can't check totalResultAmount >= amount because we need to hear back from all network stack providers to
|
||||
// correctly sort by priority
|
||||
return currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
package net.shadowfacts.phycon.component
|
||||
|
||||
import net.shadowfacts.phycon.api.NetworkDevice
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
interface NetworkStackProvider: NetworkDevice {
|
||||
interface NetworkStackProvider: NetworkDevice, ClientConfigurableDevice {
|
||||
|
||||
var providerPriority: Int
|
||||
|
||||
fun canConfigureProviderPriority(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import net.shadowfacts.phycon.block.DeviceBlockEntity
|
|||
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 org.lwjgl.glfw.GLFW
|
||||
|
||||
/**
|
||||
|
@ -63,7 +64,14 @@ class DeviceConsoleScreen(
|
|||
MinerViewController(device)
|
||||
))
|
||||
}
|
||||
|
||||
if (device is NetworkStackProvider) {
|
||||
tabs.add(TabViewController.SimpleTab(
|
||||
Label("P").apply { textColor = Color.TEXT },
|
||||
TranslatableText("gui.phycon.console.provider"),
|
||||
ProviderViewController(device),
|
||||
device::canConfigureProviderPriority
|
||||
))
|
||||
}
|
||||
|
||||
tabController = TabViewController(tabs)
|
||||
|
||||
|
|
|
@ -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.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProviderViewController<T>(
|
||||
private val device: T
|
||||
): ViewController() where T: BlockEntity, T: NetworkStackProvider {
|
||||
|
||||
override fun viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
val label = Label(TranslatableText("gui.phycon.console.provider.priority")).apply {
|
||||
textColor = Color.TEXT
|
||||
}
|
||||
view.addSubview(label)
|
||||
|
||||
val field = NumberField(device.providerPriority) {
|
||||
if (it.number != null) {
|
||||
device.providerPriority = it.number!!
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
}
|
||||
view.addSubview(field)
|
||||
|
||||
val desc = Label(TranslatableText("gui.phycon.console.provider.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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -21,6 +21,9 @@
|
|||
"gui.phycon.console.remote": "Remote Management",
|
||||
"gui.phycon.console.remote.mode": "Activation Mode",
|
||||
"gui.phycon.console.miner.mode": "Miner Mode",
|
||||
"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.redstone_mode.high": "High",
|
||||
"gui.phycon.redstone_mode.low": "Low",
|
||||
"gui.phycon.redstone_mode.toggle": "Toggle",
|
||||
|
|
Loading…
Reference in New Issue