Update pattern monitor

This commit is contained in:
DBotThePony 2023-08-18 21:05:35 +07:00
parent 182bb4c8ba
commit 0428b60561
Signed by: DBot
GPG Key ID: DCC23B5715498507
15 changed files with 218 additions and 84 deletions

View File

@ -824,6 +824,10 @@ private fun gui(provider: MatteryLanguageProvider) {
gui("matter_panel.label", "Replication request") gui("matter_panel.label", "Replication request")
gui("matter_panel.task", "Ongoing replication task") gui("matter_panel.task", "Ongoing replication task")
gui("matter_panel.task_line", "%s: %s | %s / %s") gui("matter_panel.task_line", "%s: %s | %s / %s")
gui("matter_panel.is_providing_tasks", "Tasks are dispatched to replicators")
gui("matter_panel.not_providing_tasks", "Tasks are NOT dispatched to replicators")
gui("matter_panel.cancel_all", "Cancel all tasks")
gui("matter_panel.cancel_all.desc", "Do you really want to cancel all replication tasks?")
gui("matter_panel.tasks", "Tasks") gui("matter_panel.tasks", "Tasks")
gui("matter_panel.patterns", "Patterns") gui("matter_panel.patterns", "Patterns")

View File

@ -821,6 +821,10 @@ private fun gui(provider: MatteryLanguageProvider) {
gui("matter_panel.cancel", "Отмена") gui("matter_panel.cancel", "Отмена")
gui("matter_panel.label", "Запрос на репликацию") gui("matter_panel.label", "Запрос на репликацию")
gui("matter_panel.task", "Будущий запрос на репликацию") gui("matter_panel.task", "Будущий запрос на репликацию")
gui("matter_panel.is_providing_tasks", "Задачи передаются на репликаторы")
gui("matter_panel.not_providing_tasks", "Задачи НЕ передаются на репликаторы")
gui("matter_panel.cancel_all", "Отменить все задачи")
gui("matter_panel.cancel_all.desc", "Вы действительно хотите отменить все задачи репликации?")
gui("matter_panel.tasks", "Задачи") gui("matter_panel.tasks", "Задачи")
gui("matter_panel.patterns", "Шаблоны") gui("matter_panel.patterns", "Шаблоны")

View File

@ -15,22 +15,32 @@ import net.minecraft.world.level.Level
import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.INBTSerializable
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
import ru.dbotthepony.mc.otm.core.nbt.getBoolean import ru.dbotthepony.mc.otm.core.nbt.getBoolean
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.map
import ru.dbotthepony.mc.otm.core.nbt.mapString import ru.dbotthepony.mc.otm.core.nbt.mapString
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.util.ItemSorter import ru.dbotthepony.mc.otm.core.util.ItemSorter
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.* import java.util.*
import java.util.stream.Stream import java.util.stream.Stream
class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : class MatterPanelBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_PANEL, blockPos, blockState), IReplicationTaskProvider {
MatteryDeviceBlockEntity(MBlockEntities.MATTER_PANEL, p_155229_, p_155230_), IReplicationTaskProvider { inner class PlayerSettings : INBTSerializable<CompoundTag> {
var sorter: ItemSorter = ItemSorter.DEFAULT
set(value) {
field = value
markDirtyFast()
}
var ascending: Boolean = true
set(value) {
field = value
markDirtyFast()
}
class PlayerSettings(var sorter: ItemSorter = ItemSorter.DEFAULT, var ascending: Boolean = true) : INBTSerializable<CompoundTag> {
override fun serializeNBT(): CompoundTag { override fun serializeNBT(): CompoundTag {
return CompoundTag().also { return CompoundTag().also {
it["sorter"] = sorter.name it["sorter"] = sorter.name
@ -44,20 +54,35 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
} }
var isProvidingTasks = true
set(value) {
if (field != value) {
field = value
if (value) {
_tasks.values.forEach { matterNode.graph.onMatterTaskCreated(it) }
} else {
_tasks.values.forEach { if (it.inProgress == 0) matterNode.graph.onMatterTaskRemoved(it) }
}
markDirtyFast()
}
}
private val playerSettings = Object2ObjectOpenHashMap<UUID, PlayerSettings>() private val playerSettings = Object2ObjectOpenHashMap<UUID, PlayerSettings>()
fun getPlayerSettings(ply: Player): PlayerSettings { fun getPlayerSettings(ply: Player): PlayerSettings {
return playerSettings.computeIfAbsent(ply.uuid, Object2ObjectFunction { PlayerSettings() }) return playerSettings.computeIfAbsent(ply.uuid, Object2ObjectFunction { PlayerSettings() })
} }
private val listeners = ArrayList<MatterPanelMenu>() private val listeners = WeakHashSet<MatterPanelMenu>()
val matterNode = SimpleMatterNode(tasks = this) val matterNode = SimpleMatterNode(tasks = this)
fun attachMenu(menu: MatterPanelMenu) { fun attachMenu(menu: MatterPanelMenu) {
listeners.add(menu) listeners.add(menu)
} }
fun deatachMenu(menu: MatterPanelMenu) { fun detachMenu(menu: MatterPanelMenu) {
listeners.remove(menu) listeners.remove(menu)
} }
@ -91,18 +116,18 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
} }
override fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? { override fun allocateTask(simulate: Boolean): ReplicationTaskAllocation? {
val graph = matterNode.graph as MatterGraph? ?: return null if (!isProvidingTasks) return null
for ((key, task) in _tasks) { for ((key, task) in _tasks) {
if (task.required > 0) { if (task.required > 0) {
val pattern = task.patternId.map(graph::getPattern).orElse(null) ?: continue val pattern = task.patternId.map(matterNode.graph::getPattern).orElse(null) ?: continue
if (!simulate) { if (!simulate) {
val new = task.allocate() val new = task.allocate()
_tasks[key] = new _tasks[key] = new
listeners.forEach { it.taskUpdated(new) } listeners.forEach { it.taskUpdated(new) }
graph.onMatterTaskUpdated(new, task) matterNode.graph.onMatterTaskUpdated(new, task)
setChanged() markDirtyFast()
} }
return ReplicationTaskAllocation(task, pattern) return ReplicationTaskAllocation(task, pattern)
@ -115,23 +140,21 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun notifyTaskCompletion(taskId: UUID): Boolean { override fun notifyTaskCompletion(taskId: UUID): Boolean {
var localTask = _tasks[taskId] ?: return false var localTask = _tasks[taskId] ?: return false
val oldTask = localTask val oldTask = localTask
localTask = localTask.finish() localTask = localTask.finish()
val graph = matterNode.graph as MatterGraph?
// Задача полностью выполнена // Задача полностью выполнена
if (localTask.required <= 0 && localTask.inProgress <= 0) { if (localTask.required <= 0 && localTask.inProgress <= 0) {
_tasks.remove(taskId) _tasks.remove(taskId)
graph?.onMatterTaskFinished(localTask) matterNode.graph.onMatterTaskFinished(localTask)
listeners.forEach { it.taskRemoved(localTask) } listeners.forEach { it.taskRemoved(localTask) }
} else { } else {
// Задача обновлена // Задача обновлена
_tasks[taskId] = localTask _tasks[taskId] = localTask
graph?.onMatterTaskUpdated(localTask, oldTask) matterNode.graph.onMatterTaskUpdated(localTask, oldTask)
listeners.forEach { it.taskUpdated(localTask) } listeners.forEach { it.taskUpdated(localTask) }
} }
setChanged() markDirtyFast()
return true return true
} }
@ -189,27 +212,26 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterNode.graph.onMatterTaskRemoved(task) matterNode.graph.onMatterTaskRemoved(task)
listeners.forEach { it.taskRemoved(task) } listeners.forEach { it.taskRemoved(task) }
setChanged() markDirtyFast()
} }
fun addTask(state: PatternState, count: Int): ReplicationTask { fun addTask(state: PatternState, count: Int): ReplicationTask {
val task = ReplicationTask(UUID.randomUUID(), Optional.of(state.id), state.item, 0, 0, count) val task = ReplicationTask(UUID.randomUUID(), Optional.of(state.id), state.item, 0, 0, count)
_tasks[task.id] = task _tasks[task.id] = task
matterNode.graph.onMatterTaskCreated(task) if (isProvidingTasks)
matterNode.graph.onMatterTaskCreated(task)
listeners.forEach { it.taskUpdated(task) } listeners.forEach { it.taskUpdated(task) }
setChanged() markDirtyFast()
return task return task
} }
override fun dropAllTasks() { override fun dropAllTasks() {
val graph = matterNode.graph as MatterGraph?
for (task in _tasks.values) { for (task in _tasks.values) {
graph?.onMatterTaskRemoved(task) matterNode.graph.onMatterTaskRemoved(task)
listeners.forEach { menu: MatterPanelMenu -> menu.taskUpdated(task) } listeners.forEach { it.taskRemoved(task) }
} }
_tasks.clear() _tasks.clear()

View File

@ -50,6 +50,9 @@ object Widgets18 {
val ONLY_STORE = storageGrid.next() val ONLY_STORE = storageGrid.next()
val ONLY_EXTRACT = storageGrid.next() val ONLY_EXTRACT = storageGrid.next()
val STORE_EXTRACT = storageGrid.next() val STORE_EXTRACT = storageGrid.next()
val PAUSE = storageGrid.next()
val PLAY = storageGrid.next()
val STOP = storageGrid.next()
private val miscGrid = WidgetLocation.MISC_18.grid(4, 4) private val miscGrid = WidgetLocation.MISC_18.grid(4, 4)

View File

@ -14,13 +14,14 @@ import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeBooleanRectangleButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeBooleanRectangleButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeEnumRectangleButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeRectangleButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.ScrollBarConstants import ru.dbotthepony.mc.otm.client.screen.panels.util.ScrollBarConstants
import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.asGetterSetter
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
import ru.dbotthepony.mc.otm.core.util.ItemSorter import ru.dbotthepony.mc.otm.core.util.ItemSorter
@ -54,12 +55,39 @@ class MatterPanelScreen(
val controls = DeviceControls(this, frame) val controls = DeviceControls(this, frame)
controls.sortingButtons(menu.isAscendingGS, menu.sortingGS, ItemSorter.DEFAULT) { controls.sortingButtons(menu::isAscending.asGetterSetter(), menu::sorting.asGetterSetter(), ItemSorter.DEFAULT) {
for (v in ItemSorter.entries) { for (v in ItemSorter.entries) {
add(v, skinElement = v.icon, tooltip = v.title) add(v, skinElement = v.icon, tooltip = v.title)
} }
} }
controls.addButton(
LargeBooleanRectangleButtonPanel(
this,
frame,
prop = menu::isProvidingTasks.asGetterSetter(),
iconActive = Widgets18.PLAY,
iconInactive = Widgets18.PAUSE,
tooltipActive = TranslatableComponent("otm.gui.matter_panel.is_providing_tasks"),
tooltipInactive = TranslatableComponent("otm.gui.matter_panel.not_providing_tasks"),
)
)
controls.addButton(
LargeRectangleButtonPanel(
this,
frame,
skinElement = Widgets18.STOP,
onPress = {
frame.queryUser(
TranslatableComponent("otm.gui.matter_panel.cancel_all"),
listOf(TranslatableComponent("otm.gui.matter_panel.cancel_all.desc")),
{ menu.cancelAll.accept(null) }
)
}
)
)
val scrollBar = DiscreteScrollBarPanel(this, frame, { val scrollBar = DiscreteScrollBarPanel(this, frame, {
if (isPatternView) { if (isPatternView) {
integerDivisionDown(menu.patternsFiltered.size, GRID_WIDTH) integerDivisionDown(menu.patternsFiltered.size, GRID_WIDTH)

View File

@ -9,6 +9,7 @@ import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.GetterSetter import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.value import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback
@ -20,8 +21,8 @@ abstract class BooleanRectangleButtonPanel<out S : Screen>(
width: Float, width: Float,
height: Float, height: Float,
val prop: GetterSetter<Boolean>, val prop: GetterSetter<Boolean>,
var skinElementActive: IGUIRenderable? = null, var iconActive: IGUIRenderable? = null,
var skinElementInactive: IGUIRenderable? = null, var iconInactive: IGUIRenderable? = null,
val onChange: ((newValue: Boolean) -> Unit)? = null, val onChange: ((newValue: Boolean) -> Unit)? = null,
var tooltipActive: Component? = null, var tooltipActive: Component? = null,
var tooltipInactive: Component? = null, var tooltipInactive: Component? = null,
@ -48,11 +49,17 @@ abstract class BooleanRectangleButtonPanel<out S : Screen>(
} }
if (tooltipActive != null) { if (tooltipActive != null) {
tooltips.add(tooltipActive.copy().withStyle(if (prop.get()) ChatFormatting.WHITE else ChatFormatting.GRAY)) if (prop.get())
tooltips.add(TranslatableComponent("otm.gui.tooltip.enum.active", tooltipActive.copy().withStyle(ChatFormatting.WHITE)))
else
tooltips.add(tooltipActive.copy().withStyle(ChatFormatting.GRAY))
} }
if (tooltipInactive != null) { if (tooltipInactive != null) {
tooltips.add(tooltipInactive.copy().withStyle(if (!prop.get()) ChatFormatting.WHITE else ChatFormatting.GRAY)) if (prop.get())
tooltips.add(tooltipInactive.copy().withStyle(ChatFormatting.GRAY))
else
tooltips.add(TranslatableComponent("otm.gui.tooltip.enum.active", tooltipInactive.copy().withStyle(ChatFormatting.WHITE)))
} }
graphics.renderComponentTooltip(font, tooltips, mouseX.toInt(), mouseY.toInt()) graphics.renderComponentTooltip(font, tooltips, mouseX.toInt(), mouseY.toInt())
@ -76,9 +83,9 @@ abstract class BooleanRectangleButtonPanel<out S : Screen>(
super.innerRender(graphics, mouseX, mouseY, partialTick) super.innerRender(graphics, mouseX, mouseY, partialTick)
if (prop.value) { if (prop.value) {
skinElementActive?.render(graphics, width = width, height = height) iconActive?.render(graphics, width = width, height = height)
} else { } else {
skinElementInactive?.render(graphics, width = width, height = height) iconInactive?.render(graphics, width = width, height = height)
} }
} }

View File

@ -18,7 +18,6 @@ import ru.dbotthepony.mc.otm.client.render.ItemStackIcon
import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.Dock import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.DockResizeMode
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
@ -30,7 +29,6 @@ import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.core.util.ItemSorter
import ru.dbotthepony.mc.otm.core.value import ru.dbotthepony.mc.otm.core.value
import ru.dbotthepony.mc.otm.menu.UpgradeSlots import ru.dbotthepony.mc.otm.menu.UpgradeSlots
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
@ -359,8 +357,8 @@ class DeviceControls<out S : MatteryScreen<*>>(
screen, screen,
this, this,
prop = ascending, prop = ascending,
skinElementActive = Widgets18.ARROW_UP, iconActive = Widgets18.ARROW_UP,
skinElementInactive = Widgets18.ARROW_DOWN, iconInactive = Widgets18.ARROW_DOWN,
tooltipActive = TranslatableComponent("otm.gui.sorting.ascending"), tooltipActive = TranslatableComponent("otm.gui.sorting.ascending"),
tooltipInactive = TranslatableComponent("otm.gui.sorting.descending"), tooltipInactive = TranslatableComponent("otm.gui.sorting.descending"),
).also { ).also {
@ -466,8 +464,8 @@ class DeviceControls<out S : MatteryScreen<*>>(
balanceInputsButton = addButton(LargeBooleanRectangleButtonPanel( balanceInputsButton = addButton(LargeBooleanRectangleButtonPanel(
screen, this, screen, this,
prop = balanceInputs, prop = balanceInputs,
skinElementActive = Widgets18.BALANCING_ENABLED, iconActive = Widgets18.BALANCING_ENABLED,
skinElementInactive = Widgets18.BALANCING_DISABLED).also { iconInactive = Widgets18.BALANCING_DISABLED).also {
it.tooltips.add(TranslatableComponent("otm.gui.balance_inputs")) it.tooltips.add(TranslatableComponent("otm.gui.balance_inputs"))
}) })
} else { } else {

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.mc.otm.client.screen.panels.button
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.client.render.sprites.AbstractMatterySprite import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.GetterSetter import ru.dbotthepony.mc.otm.core.GetterSetter
@ -15,12 +15,12 @@ open class LargeBooleanRectangleButtonPanel<out S : Screen>(
width: Float = SIZE, width: Float = SIZE,
height: Float = SIZE, height: Float = SIZE,
prop: GetterSetter<Boolean>, prop: GetterSetter<Boolean>,
skinElementActive: AbstractMatterySprite? = null, iconActive: IGUIRenderable? = null,
skinElementInactive: AbstractMatterySprite? = null, iconInactive: IGUIRenderable? = null,
onChange: ((newValue: Boolean) -> Unit)? = null, onChange: ((newValue: Boolean) -> Unit)? = null,
tooltipActive: Component? = null, tooltipActive: Component? = null,
tooltipInactive: Component? = null, tooltipInactive: Component? = null,
) : BooleanRectangleButtonPanel<S>(screen, parent, x, y, width, height, prop, skinElementActive, skinElementInactive, onChange, tooltipActive, tooltipInactive) { ) : BooleanRectangleButtonPanel<S>(screen, parent, x, y, width, height, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive) {
final override val IDLE = Widgets18.BUTTON_IDLE final override val IDLE = Widgets18.BUTTON_IDLE
final override val HOVERED = Widgets18.BUTTON_HOVERED final override val HOVERED = Widgets18.BUTTON_HOVERED
final override val PRESSED = Widgets18.BUTTON_PRESSED final override val PRESSED = Widgets18.BUTTON_PRESSED

View File

@ -375,12 +375,30 @@ fun <T> Comparator<in T>.nullsLast(): Comparator<T?> {
return Comparator.nullsLast(this as Comparator<in T?>) return Comparator.nullsLast(this as Comparator<in T?>)
} }
class MappedComparator<T, O>(private val parent: Comparator<O>, private val mapper: (T) -> O) : Comparator<T> {
override fun compare(o1: T, o2: T): Int {
return parent.compare(mapper.invoke(o1), mapper.invoke(o2))
}
override fun equals(other: Any?): Boolean {
return other is MappedComparator<*, *> && parent == other.parent
}
override fun hashCode(): Int {
return parent.hashCode()
}
override fun toString(): String {
return "MappedComparator[$parent]"
}
}
fun <A, B> Comparator<A>.map(mapper: (B) -> A): Comparator<B> { fun <A, B> Comparator<A>.map(mapper: (B) -> A): Comparator<B> {
return Comparator { a, b -> this@map.compare(mapper.invoke(a), mapper.invoke(b)) } return MappedComparator(this, mapper)
} }
fun <T> Comparator<T>.suppliers(): Comparator<Supplier<T>> { fun <T> Comparator<T>.suppliers(): Comparator<Supplier<T>> {
return Comparator { o1, o2 -> this@suppliers.compare(o1.get(), o2.get()) } return MappedComparator(this) { it.get() }
} }
/** /**

View File

@ -43,11 +43,7 @@ interface GetterSetter<V> : Supplier<V>, Consumer<V>, ReadWriteProperty<Any?, V>
fun watch(watch: (old: V, new: V) -> Unit): GetterSetter<V> { fun watch(watch: (old: V, new: V) -> Unit): GetterSetter<V> {
val self = this val self = this
return object : GetterSetter<V> { return object : GetterSetter<V> by self {
override fun get(): V {
return self.get()
}
override fun accept(t: V) { override fun accept(t: V) {
val old = get() val old = get()
self.accept(t) self.accept(t)
@ -116,7 +112,20 @@ interface GetterSetter<V> : Supplier<V>, Consumer<V>, ReadWriteProperty<Any?, V>
} }
} }
interface SentientGetterSetter<V> : GetterSetter<V>, ISubscriptable<V> interface SentientGetterSetter<V> : GetterSetter<V>, ISubscriptable<V> {
override fun watch(watch: (old: V, new: V) -> Unit): SentientGetterSetter<V> {
val self = this
return object : SentientGetterSetter<V> by self {
override fun accept(t: V) {
val old = get()
self.accept(t)
watch.invoke(old, t)
}
}
}
}
operator fun <T> Supplier<T>.getValue(thisRef: Any?, property: KProperty<*>): T { operator fun <T> Supplier<T>.getValue(thisRef: Any?, property: KProperty<*>): T {
return get() return get()

View File

@ -7,8 +7,23 @@ interface IMatterGraphListener {
fun onPatternRemoved(state: PatternState) {} fun onPatternRemoved(state: PatternState) {}
fun onPatternUpdated(newState: PatternState, oldState: PatternState) {} fun onPatternUpdated(newState: PatternState, oldState: PatternState) {}
/**
* This can be called any amount of times with the same task
*/
fun onMatterTaskCreated(task: ReplicationTask) {} fun onMatterTaskCreated(task: ReplicationTask) {}
/**
* This can be called any amount of times with the same task
*/
fun onMatterTaskUpdated(newState: ReplicationTask, oldState: ReplicationTask) {} fun onMatterTaskUpdated(newState: ReplicationTask, oldState: ReplicationTask) {}
/**
* This can be called any amount of times with the same task
*/
fun onMatterTaskFinished(state: ReplicationTask) {} fun onMatterTaskFinished(state: ReplicationTask) {}
/**
* This can be called any amount of times with the same task
*/
fun onMatterTaskRemoved(state: ReplicationTask) {} fun onMatterTaskRemoved(state: ReplicationTask) {}
} }

View File

@ -13,21 +13,22 @@ import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.GetterSetter import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.addSorted import ru.dbotthepony.mc.otm.core.addSorted
import ru.dbotthepony.mc.otm.core.map
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.util.BooleanValueCodec
import ru.dbotthepony.mc.otm.core.util.DecimalValueCodec import ru.dbotthepony.mc.otm.core.util.DecimalValueCodec
import ru.dbotthepony.mc.otm.core.util.ItemSorter import ru.dbotthepony.mc.otm.core.util.ItemSorter
import ru.dbotthepony.mc.otm.core.util.NullValueCodec
import ru.dbotthepony.mc.otm.core.util.codec import ru.dbotthepony.mc.otm.core.util.codec
import ru.dbotthepony.mc.otm.core.util.writeCollection import ru.dbotthepony.mc.otm.core.util.writeCollection
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
import ru.dbotthepony.mc.otm.network.* import ru.dbotthepony.mc.otm.network.*
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
import java.util.* import java.util.*
import java.util.function.Predicate import java.util.function.Predicate
import java.util.function.Supplier import java.util.function.Supplier
import kotlin.Comparator
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class CancelTaskPacket(val id: UUID) : MatteryPacket { class CancelTaskPacket(val id: UUID) : MatteryPacket {
@ -128,10 +129,10 @@ class ReplicationRequestPacket(val id: UUID, amount: Int) : MatteryPacket {
} }
class MatterPanelMenu( class MatterPanelMenu(
p_38852_: Int, containerId: Int,
inventory: Inventory, inventory: Inventory,
tile: MatterPanelBlockEntity? = null tile: MatterPanelBlockEntity? = null
) : MatteryMenu(MMenus.MATTER_PANEL, p_38852_, inventory, tile), IMatterGraphListener { ) : MatteryMenu(MMenus.MATTER_PANEL, containerId, inventory, tile), IMatterGraphListener {
fun taskUpdated(task: ReplicationTask) { fun taskUpdated(task: ReplicationTask) {
sendNetwork(TasksChangePacket(true, listOf(task))) sendNetwork(TasksChangePacket(true, listOf(task)))
} }
@ -140,25 +141,36 @@ class MatterPanelMenu(
sendNetwork(TasksChangePacket(false, listOf(task))) sendNetwork(TasksChangePacket(false, listOf(task)))
} }
val sorting: ItemSorter by mSynchronizer.ComputedField( private fun updateComparators() {
getter = { tile?.getPlayerSettings(player)?.sorter ?: ItemSorter.DEFAULT }, var p = sorting.map(PatternState::item)
codec = ItemSorter::class.codec(), var t = sorting.map(ReplicationTask::item)
observer = {
patterns.sortWith(actualComparator)
patternsFiltered.sortWith(actualComparator)
tasks.sortWith(actualTaskComparator)
tasksFiltered.sortWith(actualTaskComparator)
})
val isAscending: Boolean by mSynchronizer.ComputedField( if (!isAscending) {
getter = { tile?.getPlayerSettings(player)?.ascending ?: true }, p = p.reversed()
codec = BooleanValueCodec, t = t.reversed()
observer = { }
patterns.sortWith(actualComparator)
patternsFiltered.sortWith(actualComparator) patternComparator = p
tasks.sortWith(actualTaskComparator) taskComparator = t
tasksFiltered.sortWith(actualTaskComparator) }
})
var sorting: ItemSorter by GetterSetter.of(
mSynchronizer.ComputedField(
getter = { tile?.getPlayerSettings(player)?.sorter ?: ItemSorter.DEFAULT },
codec = ItemSorter::class.codec(),
observer = { updateComparators() }),
PlayerInput(ItemSorter::class.codec(), allowSpectators = true) { tile?.getPlayerSettings(player)?.sorter = it }
)
var isAscending: Boolean by GetterSetter.of(
mSynchronizer.ComputedBooleanField(
getter = { tile?.getPlayerSettings(player)?.ascending ?: true },
observer = { updateComparators() }),
booleanInput(allowSpectators = true) { tile?.getPlayerSettings(player)?.ascending = it }
)
var isProvidingTasks by BooleanInputWithFeedback(this, tile?.let { it::isProvidingTasks })
val cancelAll = PlayerInput(NullValueCodec) { tile?.dropAllTasks() }
val totalMatterStored: Decimal by mSynchronizer.ComputedField( val totalMatterStored: Decimal by mSynchronizer.ComputedField(
getter = { tile?.matterNode?.graph?.getMatterStorageLevel() ?: Decimal.ZERO }, getter = { tile?.matterNode?.graph?.getMatterStorageLevel() ?: Decimal.ZERO },
@ -184,14 +196,23 @@ class MatterPanelMenu(
} }
} }
val changeIsAscending = booleanInput(allowSpectators = true) { tile?.getPlayerSettings(player)?.ascending = it } private var patternComparator = sorting.map(PatternState::item)
val changeSorting = PlayerInput(ItemSorter::class.codec(), allowSpectators = true) { tile?.getPlayerSettings(player)?.sorter = it } set(value) {
if (value != field) {
field = value
patterns.sortWith(value)
patternsFiltered.sortWith(value)
}
}
val sortingGS = GetterSetter.of(::sorting, changeSorting::accept) private var taskComparator = sorting.map(ReplicationTask::item)
val isAscendingGS = GetterSetter.of(::isAscending, changeIsAscending::accept) set(value) {
if (value != field) {
private val actualComparator = Comparator<PatternState> { o1, o2 -> sorting.compare(o1.item, o2.item) * (if (isAscending) 1 else -1) } field = value
private val actualTaskComparator = Comparator<ReplicationTask> { o1, o2 -> sorting.compare(o1.item, o2.item) * (if (isAscending) 1 else -1) } tasks.sortWith(value)
tasksFiltered.sortWith(value)
}
}
private val patterns = ArrayList<PatternState>() private val patterns = ArrayList<PatternState>()
private val tasks = ArrayList<ReplicationTask>() private val tasks = ArrayList<ReplicationTask>()
@ -206,7 +227,7 @@ class MatterPanelMenu(
if (index != -1) { if (index != -1) {
this.patterns[index] = pattern this.patterns[index] = pattern
} else { } else {
this.patterns.addSorted(pattern, actualComparator) this.patterns.addSorted(pattern, patternComparator)
} }
if (filter.test(pattern.item)) { if (filter.test(pattern.item)) {
@ -215,7 +236,7 @@ class MatterPanelMenu(
if (index != -1) { if (index != -1) {
this.patternsFiltered[index] = pattern this.patternsFiltered[index] = pattern
} else { } else {
this.patternsFiltered.addSorted(pattern, actualComparator) this.patternsFiltered.addSorted(pattern, patternComparator)
} }
} }
} }
@ -234,7 +255,7 @@ class MatterPanelMenu(
if (index != -1) { if (index != -1) {
this.tasks[index] = task this.tasks[index] = task
} else { } else {
this.tasks.addSorted(task, actualTaskComparator) this.tasks.addSorted(task, taskComparator)
} }
if (filter.test(task.item)) { if (filter.test(task.item)) {
@ -243,7 +264,7 @@ class MatterPanelMenu(
if (index != -1) { if (index != -1) {
this.tasksFiltered[index] = task this.tasksFiltered[index] = task
} else { } else {
this.tasksFiltered.addSorted(task, actualTaskComparator) this.tasksFiltered.addSorted(task, taskComparator)
} }
} }
} }
@ -320,7 +341,7 @@ class MatterPanelMenu(
override fun removed(p_38940_: Player) { override fun removed(p_38940_: Player) {
super.removed(p_38940_) super.removed(p_38940_)
(tile as MatterPanelBlockEntity?)?.deatachMenu(this) (tile as MatterPanelBlockEntity?)?.detachMenu(this)
listeningGrid?.removeListener(this) listeningGrid?.removeListener(this)
} }

View File

@ -1092,12 +1092,18 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
inner class ComputedField<V>( inner class ComputedField<V>(
private val getter: () -> V, private val getter: () -> V,
private val codec: IStreamCodec<V>, private val codec: IStreamCodec<V>,
private val observer: (new: V) -> Unit = {} observer: ((new: V) -> Unit)? = null
) : AbstractField<V>(), IField<V> { ) : AbstractField<V>(), IField<V> {
private var remote: Any? = Mark private var remote: Any? = Mark
private var clientValue: Any? = Mark private var clientValue: Any? = Mark
private val subs = ISubscriptable.Impl<V>() private val subs = ISubscriptable.Impl<V>()
init {
if (observer != null) {
subs.addListener(observer)
}
}
override fun addListener(listener: Consumer<V>): ISubscriptable.L { override fun addListener(listener: Consumer<V>): ISubscriptable.L {
return subs.addListener(listener) return subs.addListener(listener)
} }
@ -1141,7 +1147,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
check(!isRemoved) { "Field was removed" } check(!isRemoved) { "Field was removed" }
val newValue = codec.read(stream) val newValue = codec.read(stream)
clientValue = newValue clientValue = newValue
observer.invoke(newValue)
subs.accept(newValue) subs.accept(newValue)
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 1020 B