Add network stack provider priorities
This commit is contained in:
parent
2d3ac4538d
commit
170e50755a
|
@ -10,7 +10,7 @@ class NumberField(
|
||||||
|
|
||||||
var number: Int?
|
var number: Int?
|
||||||
get() {
|
get() {
|
||||||
return if (text.isEmpty()) {
|
return if (isTextTemporarilyAllowed(text)) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
@ -31,7 +31,7 @@ class NumberField(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun validate(proposedText: String): Boolean {
|
override fun validate(proposedText: String): Boolean {
|
||||||
return proposedText.isEmpty() || try {
|
return isTextTemporarilyAllowed(proposedText) || try {
|
||||||
val value = Integer.parseInt(proposedText)
|
val value = Integer.parseInt(proposedText)
|
||||||
validator?.invoke(value) ?: true
|
validator?.invoke(value) ?: true
|
||||||
} catch (e: NumberFormatException) {
|
} 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.ItemAttributes
|
||||||
import alexiil.mc.lib.attributes.item.ItemInsertable
|
import alexiil.mc.lib.attributes.item.ItemInsertable
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.minecraft.block.BlockState
|
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
|
|
|
@ -44,6 +44,7 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||||
override val dispatchStackTimeout = TerminalBlockEntity.INSERTION_TIMEOUT
|
override val dispatchStackTimeout = TerminalBlockEntity.INSERTION_TIMEOUT
|
||||||
override val controller = ActivationController(40L, this)
|
override val controller = ActivationController(40L, this)
|
||||||
|
override var providerPriority = 0
|
||||||
|
|
||||||
var minerMode = MinerMode.ON_DEMAND
|
var minerMode = MinerMode.ON_DEMAND
|
||||||
|
|
||||||
|
@ -151,6 +152,10 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
return minerMode == MinerMode.AUTOMATIC
|
return minerMode == MinerMode.AUTOMATIC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun canConfigureProviderPriority(): Boolean {
|
||||||
|
return minerMode == MinerMode.ON_DEMAND
|
||||||
|
}
|
||||||
|
|
||||||
override fun toCommonTag(tag: CompoundTag) {
|
override fun toCommonTag(tag: CompoundTag) {
|
||||||
super.toCommonTag(tag)
|
super.toCommonTag(tag)
|
||||||
writeDeviceConfiguration(tag)
|
writeDeviceConfiguration(tag)
|
||||||
|
@ -164,11 +169,13 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||||
tag.putString("MinerMode", minerMode.name)
|
tag.putString("MinerMode", minerMode.name)
|
||||||
tag.putString("ActivationMode", controller.activationMode.name)
|
tag.putString("ActivationMode", controller.activationMode.name)
|
||||||
|
tag.putInt("ProviderPriority", providerPriority)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||||
minerMode = MinerMode.valueOf(tag.getString("MinerMode"))
|
minerMode = MinerMode.valueOf(tag.getString("MinerMode"))
|
||||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||||
|
providerPriority = tag.getInt("ProviderPriority")
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class MinerMode {
|
enum class MinerMode {
|
||||||
|
|
|
@ -4,7 +4,9 @@ import alexiil.mc.lib.attributes.SearchOptions
|
||||||
import alexiil.mc.lib.attributes.Simulation
|
import alexiil.mc.lib.attributes.Simulation
|
||||||
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
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.NetworkStackReceiver
|
||||||
import net.shadowfacts.phycon.component.handleItemStack
|
import net.shadowfacts.phycon.component.handleItemStack
|
||||||
import net.shadowfacts.phycon.packet.*
|
import net.shadowfacts.phycon.packet.*
|
||||||
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,11 +26,14 @@ import kotlin.math.min
|
||||||
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
||||||
ItemStackPacketHandler,
|
ItemStackPacketHandler,
|
||||||
NetworkStackProvider,
|
NetworkStackProvider,
|
||||||
NetworkStackReceiver {
|
NetworkStackReceiver,
|
||||||
|
ClientConfigurableDevice {
|
||||||
|
|
||||||
private val facing: Direction
|
private val facing: Direction
|
||||||
get() = cachedState[FaceDeviceBlock.FACING]
|
get() = cachedState[FaceDeviceBlock.FACING]
|
||||||
|
|
||||||
|
override var providerPriority = 0
|
||||||
|
|
||||||
// todo: should this be a weak ref?
|
// todo: should this be a weak ref?
|
||||||
private var inventory: GroupedItemInv? = null
|
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 alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||||
import net.minecraft.block.BlockState
|
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.inventory.Inventory
|
import net.minecraft.inventory.Inventory
|
||||||
|
@ -42,7 +41,9 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
||||||
NetworkStackDispatcher<TerminalBlockEntity.PendingInsertion> {
|
NetworkStackDispatcher<TerminalBlockEntity.PendingInsertion> {
|
||||||
|
|
||||||
companion object {
|
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
|
val INSERTION_TIMEOUT: Long = 40
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,14 +164,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
||||||
override fun tick() {
|
override fun tick() {
|
||||||
super.tick()
|
super.tick()
|
||||||
|
|
||||||
if (counter % 20 == 0L) {
|
if (!world!!.isClient) {
|
||||||
if (!world!!.isClient) {
|
finishPendingRequests()
|
||||||
finishPendingRequests()
|
finishTimedOutPendingInsertions()
|
||||||
beginInsertions()
|
}
|
||||||
finishTimedOutPendingInsertions()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (observers > 0 && !world!!.isClient) {
|
if (counter % 20 == 0L && !world!!.isClient) {
|
||||||
|
beginInsertions()
|
||||||
|
|
||||||
|
if (observers > 0) {
|
||||||
updateAndSync()
|
updateAndSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,8 +211,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
||||||
private fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
private fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
||||||
pendingRequests.remove(request)
|
pendingRequests.remove(request)
|
||||||
|
|
||||||
// todo: also sort results by interface priority
|
val sortedResults = request.results.toMutableList()
|
||||||
val sortedResults = request.results.sortedByDescending { it.first }.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
|
var amountRequested = 0
|
||||||
while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
|
while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
|
||||||
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
|
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
|
||||||
|
@ -268,6 +277,8 @@ data class StackLocateRequest(
|
||||||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||||
|
|
||||||
fun isFinishable(currentTimestamp: Long): Boolean {
|
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
|
package net.shadowfacts.phycon.component
|
||||||
|
|
||||||
import net.shadowfacts.phycon.api.NetworkDevice
|
import net.shadowfacts.phycon.api.NetworkDevice
|
||||||
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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.miner.MinerBlockEntity
|
||||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
||||||
import net.shadowfacts.phycon.component.ActivationController
|
import net.shadowfacts.phycon.component.ActivationController
|
||||||
|
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||||
import org.lwjgl.glfw.GLFW
|
import org.lwjgl.glfw.GLFW
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,7 +64,14 @@ class DeviceConsoleScreen(
|
||||||
MinerViewController(device)
|
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)
|
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": "Remote Management",
|
||||||
"gui.phycon.console.remote.mode": "Activation Mode",
|
"gui.phycon.console.remote.mode": "Activation Mode",
|
||||||
"gui.phycon.console.miner.mode": "Miner 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.high": "High",
|
||||||
"gui.phycon.redstone_mode.low": "Low",
|
"gui.phycon.redstone_mode.low": "Low",
|
||||||
"gui.phycon.redstone_mode.toggle": "Toggle",
|
"gui.phycon.redstone_mode.toggle": "Toggle",
|
||||||
|
|
Loading…
Reference in New Issue