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.task", "Ongoing replication task")
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.patterns", "Patterns")

View File

@ -821,6 +821,10 @@ private fun gui(provider: MatteryLanguageProvider) {
gui("matter_panel.cancel", "Отмена")
gui("matter_panel.label", "Запрос на репликацию")
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.patterns", "Шаблоны")

View File

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

View File

@ -50,6 +50,9 @@ object Widgets18 {
val ONLY_STORE = storageGrid.next()
val ONLY_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)

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.DeviceControls
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.slot.AbstractSlotPanel
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.core.TextComponent
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.integerDivisionDown
import ru.dbotthepony.mc.otm.core.util.ItemSorter
@ -54,12 +55,39 @@ class MatterPanelScreen(
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) {
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, {
if (isPatternView) {
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.core.GetterSetter
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.menu.input.IPlayerInputWithFeedback
@ -20,8 +21,8 @@ abstract class BooleanRectangleButtonPanel<out S : Screen>(
width: Float,
height: Float,
val prop: GetterSetter<Boolean>,
var skinElementActive: IGUIRenderable? = null,
var skinElementInactive: IGUIRenderable? = null,
var iconActive: IGUIRenderable? = null,
var iconInactive: IGUIRenderable? = null,
val onChange: ((newValue: Boolean) -> Unit)? = null,
var tooltipActive: Component? = null,
var tooltipInactive: Component? = null,
@ -48,11 +49,17 @@ abstract class BooleanRectangleButtonPanel<out S : Screen>(
}
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) {
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())
@ -76,9 +83,9 @@ abstract class BooleanRectangleButtonPanel<out S : Screen>(
super.innerRender(graphics, mouseX, mouseY, partialTick)
if (prop.value) {
skinElementActive?.render(graphics, width = width, height = height)
iconActive?.render(graphics, width = width, height = height)
} 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.screen.MatteryScreen
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.FramePanel
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.immutableList
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.menu.UpgradeSlots
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
@ -359,8 +357,8 @@ class DeviceControls<out S : MatteryScreen<*>>(
screen,
this,
prop = ascending,
skinElementActive = Widgets18.ARROW_UP,
skinElementInactive = Widgets18.ARROW_DOWN,
iconActive = Widgets18.ARROW_UP,
iconInactive = Widgets18.ARROW_DOWN,
tooltipActive = TranslatableComponent("otm.gui.sorting.ascending"),
tooltipInactive = TranslatableComponent("otm.gui.sorting.descending"),
).also {
@ -466,8 +464,8 @@ class DeviceControls<out S : MatteryScreen<*>>(
balanceInputsButton = addButton(LargeBooleanRectangleButtonPanel(
screen, this,
prop = balanceInputs,
skinElementActive = Widgets18.BALANCING_ENABLED,
skinElementInactive = Widgets18.BALANCING_DISABLED).also {
iconActive = Widgets18.BALANCING_ENABLED,
iconInactive = Widgets18.BALANCING_DISABLED).also {
it.tooltips.add(TranslatableComponent("otm.gui.balance_inputs"))
})
} 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.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.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.GetterSetter
@ -15,12 +15,12 @@ open class LargeBooleanRectangleButtonPanel<out S : Screen>(
width: Float = SIZE,
height: Float = SIZE,
prop: GetterSetter<Boolean>,
skinElementActive: AbstractMatterySprite? = null,
skinElementInactive: AbstractMatterySprite? = null,
iconActive: IGUIRenderable? = null,
iconInactive: IGUIRenderable? = null,
onChange: ((newValue: Boolean) -> Unit)? = null,
tooltipActive: 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 HOVERED = Widgets18.BUTTON_HOVERED
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?>)
}
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> {
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>> {
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> {
val self = this
return object : GetterSetter<V> {
override fun get(): V {
return self.get()
}
return object : GetterSetter<V> by self {
override fun accept(t: V) {
val old = get()
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 {
return get()

View File

@ -7,8 +7,23 @@ interface IMatterGraphListener {
fun onPatternRemoved(state: PatternState) {}
fun onPatternUpdated(newState: PatternState, oldState: PatternState) {}
/**
* This can be called any amount of times with the same task
*/
fun onMatterTaskCreated(task: ReplicationTask) {}
/**
* This can be called any amount of times with the same task
*/
fun onMatterTaskUpdated(newState: ReplicationTask, oldState: ReplicationTask) {}
/**
* This can be called any amount of times with the same task
*/
fun onMatterTaskFinished(state: ReplicationTask) {}
/**
* This can be called any amount of times with the same task
*/
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.core.GetterSetter
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.util.BooleanValueCodec
import ru.dbotthepony.mc.otm.core.util.DecimalValueCodec
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.writeCollection
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph
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.registry.MMenus
import java.util.*
import java.util.function.Predicate
import java.util.function.Supplier
import kotlin.Comparator
import kotlin.collections.ArrayList
class CancelTaskPacket(val id: UUID) : MatteryPacket {
@ -128,10 +129,10 @@ class ReplicationRequestPacket(val id: UUID, amount: Int) : MatteryPacket {
}
class MatterPanelMenu(
p_38852_: Int,
containerId: Int,
inventory: Inventory,
tile: MatterPanelBlockEntity? = null
) : MatteryMenu(MMenus.MATTER_PANEL, p_38852_, inventory, tile), IMatterGraphListener {
) : MatteryMenu(MMenus.MATTER_PANEL, containerId, inventory, tile), IMatterGraphListener {
fun taskUpdated(task: ReplicationTask) {
sendNetwork(TasksChangePacket(true, listOf(task)))
}
@ -140,25 +141,36 @@ class MatterPanelMenu(
sendNetwork(TasksChangePacket(false, listOf(task)))
}
val sorting: ItemSorter by mSynchronizer.ComputedField(
getter = { tile?.getPlayerSettings(player)?.sorter ?: ItemSorter.DEFAULT },
codec = ItemSorter::class.codec(),
observer = {
patterns.sortWith(actualComparator)
patternsFiltered.sortWith(actualComparator)
tasks.sortWith(actualTaskComparator)
tasksFiltered.sortWith(actualTaskComparator)
})
private fun updateComparators() {
var p = sorting.map(PatternState::item)
var t = sorting.map(ReplicationTask::item)
val isAscending: Boolean by mSynchronizer.ComputedField(
getter = { tile?.getPlayerSettings(player)?.ascending ?: true },
codec = BooleanValueCodec,
observer = {
patterns.sortWith(actualComparator)
patternsFiltered.sortWith(actualComparator)
tasks.sortWith(actualTaskComparator)
tasksFiltered.sortWith(actualTaskComparator)
})
if (!isAscending) {
p = p.reversed()
t = t.reversed()
}
patternComparator = p
taskComparator = t
}
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(
getter = { tile?.matterNode?.graph?.getMatterStorageLevel() ?: Decimal.ZERO },
@ -184,14 +196,23 @@ class MatterPanelMenu(
}
}
val changeIsAscending = booleanInput(allowSpectators = true) { tile?.getPlayerSettings(player)?.ascending = it }
val changeSorting = PlayerInput(ItemSorter::class.codec(), allowSpectators = true) { tile?.getPlayerSettings(player)?.sorter = it }
private var patternComparator = sorting.map(PatternState::item)
set(value) {
if (value != field) {
field = value
patterns.sortWith(value)
patternsFiltered.sortWith(value)
}
}
val sortingGS = GetterSetter.of(::sorting, changeSorting::accept)
val isAscendingGS = GetterSetter.of(::isAscending, changeIsAscending::accept)
private val actualComparator = Comparator<PatternState> { o1, o2 -> sorting.compare(o1.item, o2.item) * (if (isAscending) 1 else -1) }
private val actualTaskComparator = Comparator<ReplicationTask> { o1, o2 -> sorting.compare(o1.item, o2.item) * (if (isAscending) 1 else -1) }
private var taskComparator = sorting.map(ReplicationTask::item)
set(value) {
if (value != field) {
field = value
tasks.sortWith(value)
tasksFiltered.sortWith(value)
}
}
private val patterns = ArrayList<PatternState>()
private val tasks = ArrayList<ReplicationTask>()
@ -206,7 +227,7 @@ class MatterPanelMenu(
if (index != -1) {
this.patterns[index] = pattern
} else {
this.patterns.addSorted(pattern, actualComparator)
this.patterns.addSorted(pattern, patternComparator)
}
if (filter.test(pattern.item)) {
@ -215,7 +236,7 @@ class MatterPanelMenu(
if (index != -1) {
this.patternsFiltered[index] = pattern
} else {
this.patternsFiltered.addSorted(pattern, actualComparator)
this.patternsFiltered.addSorted(pattern, patternComparator)
}
}
}
@ -234,7 +255,7 @@ class MatterPanelMenu(
if (index != -1) {
this.tasks[index] = task
} else {
this.tasks.addSorted(task, actualTaskComparator)
this.tasks.addSorted(task, taskComparator)
}
if (filter.test(task.item)) {
@ -243,7 +264,7 @@ class MatterPanelMenu(
if (index != -1) {
this.tasksFiltered[index] = task
} else {
this.tasksFiltered.addSorted(task, actualTaskComparator)
this.tasksFiltered.addSorted(task, taskComparator)
}
}
}
@ -320,7 +341,7 @@ class MatterPanelMenu(
override fun removed(p_38940_: Player) {
super.removed(p_38940_)
(tile as MatterPanelBlockEntity?)?.deatachMenu(this)
(tile as MatterPanelBlockEntity?)?.detachMenu(this)
listeningGrid?.removeListener(this)
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 1020 B