Portable condensation drive now use new item filter

Item filter now supports tag and nbt matching
This commit is contained in:
DBotThePony 2022-05-16 13:54:04 +07:00
parent 86c706a178
commit 89581bbb52
Signed by: DBot
GPG Key ID: DCC23B5715498507
9 changed files with 218 additions and 402 deletions

View File

@ -50,6 +50,10 @@ public class FlexGridPanel extends EditablePanel {
// список потомков
var children = getUndockedChildren();
if (children.size() == 0) {
return;
}
// хранит общую ширину всех потомков в ряд
// а так же ограничитель ширины ряда после
// определения количества рядов

View File

@ -233,24 +233,6 @@ public class MatteryNetworking {
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
);
CHANNEL.registerMessage(
next_network_id++,
DriveViewerMenu.FilterSwitchPacket.class,
DriveViewerMenu.FilterSwitchPacket::write,
DriveViewerMenu.FilterSwitchPacket::read,
DriveViewerMenu.FilterSwitchPacket::play,
Optional.of(NetworkDirection.PLAY_TO_SERVER)
);
CHANNEL.registerMessage(
next_network_id++,
DriveViewerMenu.FilterSetPacket.class,
DriveViewerMenu.FilterSetPacket::write,
DriveViewerMenu.FilterSetPacket::read,
DriveViewerMenu.FilterSetPacket::play,
Optional.of(NetworkDirection.PLAY_TO_SERVER)
);
CHANNEL.registerMessage(
next_network_id++,
EnergyCounterPacket.class,

View File

@ -6,11 +6,8 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem.FilterSettings
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu.FilterSetPacket
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu.FilterSwitchPacket
import ru.dbotthepony.mc.otm.network.MatteryNetworking
class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Component) :
MatteryScreen<DriveViewerMenu>(menu, inventory, title) {
@ -86,134 +83,13 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp
settings.add(dock_left)
settings.add(grid_filter)
for (i in 0 until FilterSettings.MAX_FILTERS) {
object : AbstractSlotPanel(this@DriveViewerScreen, grid_filter, 0f, 0f) {
override fun getItemStack(): ItemStack {
val filter = menu.getFilter() ?: return ItemStack.EMPTY
return filter.items[i]
}
private var clicking = false
override fun mouseClickedInner(mouse_x: Double, mouse_y: Double, mouse_click_type: Int): Boolean {
clicking = true
return true
}
override fun mouseReleasedInner(mouse_x: Double, mouse_y: Double, flag: Int): Boolean {
if (clicking)
MatteryNetworking.send(null, FilterSetPacket(menu.containerId, i, menu.carried))
clicking = false
return true
}
}
for (i in 0 until PortableCondensationDriveItem.MAX_FILTERS) {
FilterSlotPanel(this, grid_filter, menu.driveFilterSlots[i], 0f, 0f)
}
val no = TranslatableComponent("otm.filter.no")
val yes = TranslatableComponent("otm.filter.yes")
val matchNbt =
object : ButtonPanel(this@DriveViewerScreen, dock_left, 0f, 0f, 90f, 20f, TranslatableComponent("otm.filter.match_nbt", no)) {
override fun tick() {
super.tick()
val filter = menu.getFilter()
if (filter != null) {
widget?.message = TranslatableComponent("otm.filter.match_nbt", if (filter.matchNbt) yes else no)
widget?.active = !isWidgetDisabled
} else {
widget?.active = false
}
}
override fun onPress() {
super.onPress()
val filter = menu.getFilter()
if (filter != null) {
MatteryNetworking.send(
null,
FilterSwitchPacket(
menu.containerId,
DriveViewerMenu.FilterSwitch.MATCH_NBT,
!filter.matchNbt
)
)
disableTicks = 20
}
}
}
val matchTag =
object : ButtonPanel(this@DriveViewerScreen, dock_left, 0f, 0f, 90f, 20f, TranslatableComponent("otm.filter.match_tag", no)) {
override fun tick() {
super.tick()
val filter = menu.getFilter()
if (filter != null) {
widget?.message = TranslatableComponent("otm.filter.match_tag", if (filter.matchTag) yes else no)
widget?.active = !isWidgetDisabled
} else {
widget?.active = false
}
}
override fun onPress() {
super.onPress()
val filter = menu.getFilter()
if (filter != null) {
MatteryNetworking.send(
null,
FilterSwitchPacket(
menu.containerId,
DriveViewerMenu.FilterSwitch.MATCH_TAG,
!filter.matchTag
)
)
disableTicks = 20
}
}
}
val blacklist =
object : ButtonPanel(this@DriveViewerScreen, dock_left, 0f, 0f, 90f, 20f, TranslatableComponent("otm.filter.blacklist", no)) {
override fun tick() {
super.tick()
val filter = menu.getFilter()
if (filter != null) {
widget?.message = TranslatableComponent("otm.filter.blacklist", if (filter.isBlacklist) yes else no)
widget?.active = !isWidgetDisabled
} else {
widget?.active = false
}
}
override fun onPress() {
super.onPress()
val filter = menu.getFilter()
if (filter != null) {
MatteryNetworking.send(
null,
FilterSwitchPacket(
menu.containerId,
DriveViewerMenu.FilterSwitch.BLACKLIST,
!filter.isBlacklist
)
)
disableTicks = 20
}
}
}
matchNbt.setDockMargin(0f, 4f, 0f, 0f)
matchTag.setDockMargin(0f, 4f, 0f, 0f)
blacklist.setDockMargin(0f, 4f, 0f, 0f)
CheckBoxLabelInputPanel(this, dock_left, menu.isWhitelist, TranslatableComponent("otm.gui.filter.is_whitelist"), width = 90f, height = 20f).also { it.setDockMargin(0f, 4f, 0f, 0f) }
CheckBoxLabelInputPanel(this, dock_left, menu.matchTag, TranslatableComponent("otm.gui.filter.match_tag"), width = 90f, height = 20f).also { it.setDockMargin(0f, 4f, 0f, 0f) }
CheckBoxLabelInputPanel(this, dock_left, menu.matchNBT, TranslatableComponent("otm.gui.filter.match_nbt"), width = 90f, height = 20f).also { it.setDockMargin(0f, 4f, 0f, 0f) }
for (panel in settings) {
panel.visible = false

View File

@ -4,6 +4,8 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.tags.TagKey
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.network.NetworkEvent
@ -12,6 +14,7 @@ import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.set
import java.util.Arrays
import java.util.LinkedList
import java.util.function.Supplier
@ -42,7 +45,12 @@ data class ItemFilterSlotPacket(val slotID: Int, val newValue: ItemStack) {
fun playServer(player: ServerPlayer) {
val menu = player.containerMenu as? MatteryMenu ?: return LOGGER.error("No MatteryMenu is open right now, can't handle ItemFilterSlotReplicaPacket from $player")
menu.filterSlots.getOrNull(slotID)?.set(newValue) //?: LOGGER.error("ItemFilterSlotReplicaPacket: unknown slot $slotID from $player in $menu!")
val slot = menu.filterSlots.getOrNull(slotID) ?: return LOGGER.error("ItemFilterSlotReplicaPacket: unknown slot $slotID from $player in $menu!")
if (slot.filter?.isLocked == true)
return
slot.set(newValue)
}
companion object {
@ -54,11 +62,11 @@ data class ItemFilterSlotPacket(val slotID: Int, val newValue: ItemStack) {
}
}
data class ItemFilterNetworkSlot(val slotID: Int, val networkID: Int, val filter: ItemFilter?) {
data class ItemFilterNetworkSlot(val slotID: Int, val networkID: Int, var filter: ItemFilter?) {
fun get() = filter?.get(slotID) ?: remote
fun set(value: ItemStack) {
if (filter != null)
filter[slotID] = value
filter!![slotID] = value
else
remote = value
}
@ -77,21 +85,85 @@ data class ItemFilterNetworkSlot(val slotID: Int, val networkID: Int, val filter
}
}
fun interface ItemFilterCallback {
fun invoke(slot: Int?, oldValue: ItemStack?, newValue: ItemStack?)
}
fun interface ItemFilterFullCallback {
fun invoke(self: ItemFilter, slot: Int?, oldValue: ItemStack?, newValue: ItemStack?)
}
class ItemFilter(
val size: Int,
private val modified: (slot: Int?, oldValue: ItemStack?, newValue: ItemStack?) -> Unit
private val modified: ItemFilterFullCallback? = null
) : INBTSerializable<CompoundTag> {
constructor(size: Int, modified: ItemFilterCallback?) :
this(size,
modified?.let {
fn ->
return@let ItemFilterFullCallback { _: ItemFilter, slot: Int?, oldValue: ItemStack?, newValue: ItemStack? -> fn.invoke(slot, oldValue, newValue) }
})
private val filter = Array<ItemStack>(size) { ItemStack.EMPTY }
private val linkedFilter = LinkedList<ItemStack>()
var isLocked = false
var isWhitelist = false
set(value) {
if (value != field) {
field = value
modified.invoke(null, null, null)
modified?.invoke(this, null, null, null)
}
}
var matchTag = false
set(value) {
if (value != field) {
field = value
modified?.invoke(this, null, null, null)
}
}
var matchNBT = false
set(value) {
if (value != field) {
field = value
modified?.invoke(this, null, null, null)
}
}
fun clear() {
isWhitelist = false
matchTag = false
matchNBT = false
Arrays.fill(filter, ItemStack.EMPTY)
linkedFilter.clear()
modified?.invoke(this, null, null, null)
}
fun copyFrom(other: ItemFilter) {
require(other.size == size) { "Size differs (this filter has size of $size, other has size of ${other.size})" }
linkedFilter.clear()
for (i in 0 until size) {
filter[i] = other.filter[i]
if (!filter[i].isEmpty) {
linkedFilter.add(filter[i])
}
}
isWhitelist = other.isWhitelist
matchTag = other.matchTag
matchNBT = other.matchNBT
modified?.invoke(this, null, null, null)
}
operator fun set(index: Int, value: ItemStack) {
if (value.isEmpty && filter[index].isEmpty) {
return
@ -100,14 +172,17 @@ class ItemFilter(
val old = filter[index]
filter[index] = value.let { if (!it.isEmpty) it.copy().also { it.count = 1 } else it }
if (!filter[index].isEmpty && filter[index].tag != null && filter[index].tag!!.isEmpty) {
filter[index].tag = null
}
if (!old.isEmpty)
linkedFilter.remove(old)
if (!filter[index].isEmpty)
linkedFilter.add(filter[index])
modified.invoke(index, old, filter[index])
modified?.invoke(this, index, old, filter[index])
}
operator fun get(index: Int): ItemStack = filter[index].copy()
@ -121,24 +196,48 @@ class ItemFilter(
return !isWhitelist
}
if (isWhitelist) {
for (item in linkedFilter) {
if (item.`is`(value.item)) {
return true
for (item in linkedFilter) {
var matched = item.`is`(value.item)
if (matched && matchTag) {
matched = false
val thisTags = item.tags
val stackTags = HashSet<TagKey<Item>>()
for (tag in value.tags) {
stackTags.add(tag)
}
for (tag1 in thisTags) {
if (stackTags.contains(tag1)) {
matched = true
break
}
}
}
return false
}
if (matched && matchNBT) {
val a = item.tag
val b = value.tag
if (a == null && b == null) {
// nothing
} else if (a != null && b != null) {
matched = a == b
} else if (a != null) {
matched = a.isEmpty
} else {
matched = false
}
}
for (item in linkedFilter) {
if (item.`is`(value.item)) {
return false
if (matched) {
return isWhitelist
}
}
return true
return !isWhitelist
}
override fun serializeNBT(): CompoundTag {
@ -150,6 +249,8 @@ class ItemFilter(
}
it["is_whitelist"] = isWhitelist
it["match_tag"] = matchTag
it["match_nbt"] = matchNBT
}
}
@ -169,5 +270,7 @@ class ItemFilter(
}
isWhitelist = nbt.getBoolean("is_whitelist")
matchTag = nbt.getBoolean("match_tag")
matchNBT = nbt.getBoolean("match_nbt")
}
}

View File

@ -24,7 +24,9 @@ import net.minecraftforge.event.ForgeEventFactory
import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.event.entity.player.EntityItemPickupEvent
import ru.dbotthepony.mc.otm.capability.drive.DrivePool
import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
import java.util.*
@ -92,117 +94,18 @@ class PortableCondensationDriveItem(capacity: Int) :
return DriveCapability(stack)
}
class FilterSettings() {
@JvmField
val items = Array<ItemStack>(MAX_FILTERS) { ItemStack.EMPTY }
@JvmField
var matchNbt = false
@JvmField
var matchTag = false
@JvmField
var isBlacklist = false
constructor(tag: CompoundTag) : this() {
val list = tag.getList("filter", Tag.TAG_COMPOUND.toInt())
var i = 0
for (tag in list) {
if (tag is CompoundTag) {
items[i++] = ItemStack.of(tag)
}
}
matchNbt = tag.getBoolean("match_nbt")
matchTag = tag.getBoolean("match_tag")
isBlacklist = tag.getBoolean("blacklist")
}
fun serializeNBT(compound: CompoundTag) {
val list = ListTag()
for (i in 0 until MAX_FILTERS) {
list.add(items[i].serializeNBT())
}
compound["filter"] = list
compound["match_nbt"] = matchNbt
compound["match_tag"] = matchTag
compound["blacklist"] = isBlacklist
}
fun serializeNBT(drive: ItemStack) {
serializeNBT(drive.orCreateTag)
}
fun matches(stack: ItemStack): Boolean {
if (isBlacklist) {
for (item in items) {
if (!matchNbt && ItemStack.isSame(item, stack)) {
return false
}
if (matchTag) {
val thisTags = item.tags
val stackTatgs = stack.tags.toArray()
for (tag1 in thisTags) {
if (stackTatgs.contains(tag1)) {
return false
}
}
}
if (matchNbt && ItemStack.isSameItemSameTags(item, stack)) {
return false
}
}
return true
} else {
for (item in items) {
var same = ItemStack.isSame(item, stack)
if (!same && matchTag) {
val thisTags = item.tags
val stackTatgs = stack.tags.toArray()
for (tag1 in thisTags) {
if (stackTatgs.contains(tag1)) {
same = true
break
}
}
}
if (matchNbt) {
if (same && ItemStack.tagMatches(item, stack)) {
return true
}
} else {
if (same) {
return true
}
}
}
return false
}
}
companion object {
const val MAX_FILTERS = 12
}
}
fun getFilterSettings(drive: ItemStack): FilterSettings {
return FilterSettings(drive.orCreateTag)
fun getFilterSettings(drive: ItemStack): ItemFilter {
val filter = ItemFilter(MAX_FILTERS)
filter.isWhitelist = true
drive.tag?.ifHas(FILTER_PATH, CompoundTag::class.java, filter::deserializeNBT)
return filter
}
@Suppress("unused")
companion object {
const val MAX_FILTERS = 4 * 3
const val FILTER_PATH = "filter"
@SubscribeEvent
fun onPickupEvent(event: EntityItemPickupEvent) {
if (event.item.owner != null && event.item.owner != event.player.uuid && event.item.age < 200) {
@ -221,7 +124,7 @@ class PortableCondensationDriveItem(capacity: Int) :
stack.getCapability(MatteryCapability.DRIVE).ifPresent {
val filter = drive.getFilterSettings(stack)
if (filter.matches(event.item.item)) {
if (filter.match(event.item.item)) {
val copy = event.item.item.copy()
val remaining = (it as ItemMatteryDrive).insertStack(event.item.item, false)

View File

@ -1,24 +1,23 @@
package ru.dbotthepony.mc.otm.menu
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraftforge.energy.CapabilityEnergy
import net.minecraftforge.network.NetworkEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.block.entity.DriveViewerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive
import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.ifPresentK
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem.FilterSettings
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputWidget
import ru.dbotthepony.mc.otm.registry.MMenus
import ru.dbotthepony.mc.otm.storage.ITEM_STORAGE
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
import ru.dbotthepony.mc.otm.storage.PoweredVirtualComponent
import java.util.function.Supplier
class DriveViewerMenu @JvmOverloads constructor(
containerID: Int,
@ -27,9 +26,10 @@ class DriveViewerMenu @JvmOverloads constructor(
) : MatteryPoweredMenu(
MMenus.DRIVE_VIEWER, containerID, inventory, tile
), INetworkedItemViewSupplier {
val view: NetworkedItemView
private val powered: PoweredVirtualComponent<ItemStackWrapper>?
val view = NetworkedItemView(inventory.player, this, tile == null)
val driveSlot: MatterySlot
private val powered: PoweredVirtualComponent<ItemStackWrapper>?
private var lastDrive: IMatteryDrive<ItemStackWrapper>? = null
override fun getNetworkedItemView() = view
@ -43,8 +43,6 @@ class DriveViewerMenu @JvmOverloads constructor(
}
}
view = NetworkedItemView(inventory.player, this, tile == null)
if (tile != null) {
powered = PoweredVirtualComponent(
ItemStackWrapper::class.java,
@ -60,6 +58,26 @@ class DriveViewerMenu @JvmOverloads constructor(
addInventorySlots()
}
val driveFilter = ItemFilter(PortableCondensationDriveItem.MAX_FILTERS) { self, _, _, _ ->
if (tile?.container?.get(0)?.item is PortableCondensationDriveItem) {
tile.container[0].getOrCreateTag().put(PortableCondensationDriveItem.FILTER_PATH, self.serializeNBT())
}
}
val driveFilterSlots = addFilterSlots(driveFilter)
val isWhitelist = BooleanPlayerInputWidget(this)
val matchTag = BooleanPlayerInputWidget(this)
val matchNBT = BooleanPlayerInputWidget(this)
init {
if (tile == null) {
isWhitelist.asClient()
matchTag.asClient()
matchNBT.asClient()
}
}
override fun broadcastChanges() {
super.broadcastChanges()
@ -70,21 +88,44 @@ class DriveViewerMenu @JvmOverloads constructor(
lastDrive = null
if (!itemStack.isEmpty) {
itemStack.getCapability(MatteryCapability.DRIVE).ifPresent {
if (it.storageType === OverdriveThatMatters.INSTANCE.ITEM_STORAGE()) {
itemStack.getCapability(MatteryCapability.DRIVE).ifPresentK {
if (it.storageType === ITEM_STORAGE) {
lastDrive = it as IMatteryDrive<ItemStackWrapper>
}
}
}
if (prev != lastDrive) {
if (prev != null)
powered!!.remove(prev)
prev?.let(powered!!::remove)
view.clear()
lastDrive?.let(powered!!::add)
if (lastDrive != null)
powered!!.add(lastDrive!!)
if (lastDrive != null) {
val filter = (itemStack.item as? PortableCondensationDriveItem)?.getFilterSettings(itemStack)
if (filter != null) {
driveFilter.copyFrom(filter)
driveFilter.isLocked = false
isWhitelist.withProperty(driveFilter::isWhitelist)
matchTag.withProperty(driveFilter::matchTag)
matchNBT.withProperty(driveFilter::matchNBT)
} else {
driveFilter.clear()
driveFilter.isLocked = true
isWhitelist.withoutAnything()
matchTag.withoutAnything()
matchNBT.withoutAnything()
}
} else {
driveFilter.clear()
driveFilter.isLocked = true
isWhitelist.withoutAnything()
matchTag.withoutAnything()
matchNBT.withoutAnything()
}
}
view.network()
@ -102,10 +143,10 @@ class DriveViewerMenu @JvmOverloads constructor(
override fun removed(p_38940_: Player) {
super.removed(p_38940_)
if (powered != null)
lastDrive?.removeListener(powered)
if (lastDrive != null)
powered?.remove(lastDrive!!)
view.clear()
view.removed()
}
override fun quickMoveStack(ply: Player, slot_index: Int): ItemStack {
@ -135,107 +176,4 @@ class DriveViewerMenu @JvmOverloads constructor(
slot.setChanged()
return copy
}
enum class FilterSwitch {
MATCH_NBT, MATCH_TAG, BLACKLIST
}
fun getFilter(): FilterSettings? {
if (driveSlot.item.isEmpty)
return null
val item = driveSlot.item.item
return if (item is PortableCondensationDriveItem) item.getFilterSettings(driveSlot.item) else null
}
class FilterSetPacket(val id: Int, val slot: Int, val value: ItemStack) {
fun write(buffer: FriendlyByteBuf) {
buffer.writeInt(id)
buffer.writeInt(slot)
buffer.writeItem(value)
}
fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
if (slot < 0 || slot >= FilterSettings.MAX_FILTERS)
return
if (value.count > 1)
value.count = 1
context.get().enqueueWork {
val ply = context.get().sender!!
val menu = ply.containerMenu
if (menu is DriveViewerMenu && menu.containerId == id) {
if (menu.driveSlot.item.isEmpty)
return@enqueueWork
val itemStack = menu.driveSlot.item
val item = itemStack.item
if (item is PortableCondensationDriveItem) {
val filter = item.getFilterSettings(itemStack)
filter.items[slot] = value
filter.serializeNBT(itemStack)
}
}
}
}
companion object {
@JvmStatic
fun read(buffer: FriendlyByteBuf): FilterSetPacket {
return FilterSetPacket(buffer.readInt(), buffer.readInt(), buffer.readItem())
}
}
}
class FilterSwitchPacket(val id: Int, val type: FilterSwitch, val value: Boolean) {
fun write(buffer: FriendlyByteBuf) {
buffer.writeInt(id)
buffer.writeEnum(type)
buffer.writeBoolean(value)
}
fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
val ply = context.get().sender!!
val menu = ply.containerMenu
if (menu is DriveViewerMenu && menu.containerId == id) {
val settings = menu.getFilter() ?: return@enqueueWork
when (type) {
FilterSwitch.MATCH_NBT -> {
settings.matchNbt = value
}
FilterSwitch.MATCH_TAG -> {
settings.matchTag = value
}
FilterSwitch.BLACKLIST -> {
settings.isBlacklist = value
}
}
settings.serializeNBT(menu.driveSlot.item)
}
}
}
companion object {
@JvmStatic
fun read(buffer: FriendlyByteBuf): FilterSwitchPacket {
return FilterSwitchPacket(
buffer.readInt(),
buffer.readEnum(FilterSwitch::class.java),
buffer.readBoolean()
)
}
}
}
}

View File

@ -55,6 +55,18 @@ class BooleanPlayerInputWidget(menu: MatteryMenu) : AbstractWidget(menu) {
return this
}
fun withProperty(state: KMutableProperty0<Boolean>): BooleanPlayerInputWidget {
withClicker { state.set(it) }
withSupplier { state.get() }
return this
}
fun withoutAnything(): BooleanPlayerInputWidget {
supplier = null
clicker = null
return this
}
fun asClient(): BooleanPlayerInputWidget {
supplier = null
clicker = {

View File

@ -35,13 +35,13 @@ open class VirtualComponent<T : IStorageStack>(type: StorageStackType<T>) : IVir
override val storageType: StorageStackType<T> = type
// удаленный UUID -> Кортеж
protected val remoteByUUID: MutableMap<UUID, RemoteTuple<T>> = HashMap()
protected val remoteByUUID = HashMap<UUID, RemoteTuple<T>>()
// локальный UUID -> Локальный кортеж
protected val localByUUID: MutableMap<UUID, LocalTuple<T>> = HashMap()
protected val localByUUID = HashMap<UUID, LocalTuple<T>>()
// Стак -> Локальный кортеж стака
protected val tuples: MutableMap<T, LocalTuple<T>> = HashMap()
protected val tuples = HashMap<T, LocalTuple<T>>()
// ArrayList для скорости работы
protected val listeners = ArrayList<IStorageListener<T>>()

View File

@ -36,6 +36,8 @@
"otm.gui.matter.name": "MtU",
"otm.gui.filter.is_whitelist": "Is Whitelist",
"otm.gui.filter.match_nbt": "Match NBT",
"otm.gui.filter.match_tag": "Match Tag",
"otm.gui.android_research": "Research Tree",
@ -88,10 +90,6 @@
"otm.filter.yes": "Yes",
"otm.filter.no": "No",
"otm.filter.match_nbt": "Match NBT: %s",
"otm.filter.match_tag": "Match Tag: %s",
"otm.filter.blacklist": "Blacklist: %s",
"otm.matter_bottler.switch_mode": "Switch work mode",
"android_feature.overdrive_that_matters.air_bags": "Air Bags",