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(); var children = getUndockedChildren();
if (children.size() == 0) {
return;
}
// хранит общую ширину всех потомков в ряд // хранит общую ширину всех потомков в ряд
// а так же ограничитель ширины ряда после // а так же ограничитель ширины ряда после
// определения количества рядов // определения количества рядов

View File

@ -233,24 +233,6 @@ public class MatteryNetworking {
Optional.of(NetworkDirection.PLAY_TO_CLIENT) 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( CHANNEL.registerMessage(
next_network_id++, next_network_id++,
EnergyCounterPacket.class, EnergyCounterPacket.class,

View File

@ -6,11 +6,8 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel 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
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) : class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Component) :
MatteryScreen<DriveViewerMenu>(menu, inventory, title) { MatteryScreen<DriveViewerMenu>(menu, inventory, title) {
@ -86,134 +83,13 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp
settings.add(dock_left) settings.add(dock_left)
settings.add(grid_filter) settings.add(grid_filter)
for (i in 0 until FilterSettings.MAX_FILTERS) { for (i in 0 until PortableCondensationDriveItem.MAX_FILTERS) {
object : AbstractSlotPanel(this@DriveViewerScreen, grid_filter, 0f, 0f) { FilterSlotPanel(this, grid_filter, menu.driveFilterSlots[i], 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
}
}
} }
val no = TranslatableComponent("otm.filter.no") CheckBoxLabelInputPanel(this, dock_left, menu.isWhitelist, TranslatableComponent("otm.gui.filter.is_whitelist"), width = 90f, height = 20f).also { it.setDockMargin(0f, 4f, 0f, 0f) }
val yes = TranslatableComponent("otm.filter.yes") 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) }
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)
for (panel in settings) { for (panel in settings) {
panel.visible = false panel.visible = false

View File

@ -4,6 +4,8 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag import net.minecraft.nbt.ListTag
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer 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.minecraft.world.item.ItemStack
import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.network.NetworkEvent 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.ifHas
import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.set import ru.dbotthepony.mc.otm.set
import java.util.Arrays
import java.util.LinkedList import java.util.LinkedList
import java.util.function.Supplier import java.util.function.Supplier
@ -42,7 +45,12 @@ data class ItemFilterSlotPacket(val slotID: Int, val newValue: ItemStack) {
fun playServer(player: ServerPlayer) { 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") 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 { 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 get() = filter?.get(slotID) ?: remote
fun set(value: ItemStack) { fun set(value: ItemStack) {
if (filter != null) if (filter != null)
filter[slotID] = value filter!![slotID] = value
else else
remote = value 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( class ItemFilter(
val size: Int, val size: Int,
private val modified: (slot: Int?, oldValue: ItemStack?, newValue: ItemStack?) -> Unit private val modified: ItemFilterFullCallback? = null
) : INBTSerializable<CompoundTag> { ) : 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 filter = Array<ItemStack>(size) { ItemStack.EMPTY }
private val linkedFilter = LinkedList<ItemStack>() private val linkedFilter = LinkedList<ItemStack>()
var isLocked = false
var isWhitelist = false var isWhitelist = false
set(value) { set(value) {
if (value != field) { if (value != field) {
field = value 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) { operator fun set(index: Int, value: ItemStack) {
if (value.isEmpty && filter[index].isEmpty) { if (value.isEmpty && filter[index].isEmpty) {
return return
@ -100,14 +172,17 @@ class ItemFilter(
val old = filter[index] val old = filter[index]
filter[index] = value.let { if (!it.isEmpty) it.copy().also { it.count = 1 } else it } 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) if (!old.isEmpty)
linkedFilter.remove(old) linkedFilter.remove(old)
if (!filter[index].isEmpty) if (!filter[index].isEmpty)
linkedFilter.add(filter[index]) 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() operator fun get(index: Int): ItemStack = filter[index].copy()
@ -121,24 +196,48 @@ class ItemFilter(
return !isWhitelist return !isWhitelist
} }
if (isWhitelist) { for (item in linkedFilter) {
for (item in linkedFilter) { var matched = item.`is`(value.item)
if (item.`is`(value.item)) {
return true 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 (matched) {
if (item.`is`(value.item)) { return isWhitelist
return false
} }
} }
return true return !isWhitelist
} }
override fun serializeNBT(): CompoundTag { override fun serializeNBT(): CompoundTag {
@ -150,6 +249,8 @@ class ItemFilter(
} }
it["is_whitelist"] = isWhitelist it["is_whitelist"] = isWhitelist
it["match_tag"] = matchTag
it["match_nbt"] = matchNBT
} }
} }
@ -169,5 +270,7 @@ class ItemFilter(
} }
isWhitelist = nbt.getBoolean("is_whitelist") 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.eventbus.api.SubscribeEvent
import net.minecraftforge.event.entity.player.EntityItemPickupEvent import net.minecraftforge.event.entity.player.EntityItemPickupEvent
import ru.dbotthepony.mc.otm.capability.drive.DrivePool 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.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set import ru.dbotthepony.mc.otm.set
import java.util.* import java.util.*
@ -92,117 +94,18 @@ class PortableCondensationDriveItem(capacity: Int) :
return DriveCapability(stack) return DriveCapability(stack)
} }
class FilterSettings() { fun getFilterSettings(drive: ItemStack): ItemFilter {
@JvmField val filter = ItemFilter(MAX_FILTERS)
val items = Array<ItemStack>(MAX_FILTERS) { ItemStack.EMPTY } filter.isWhitelist = true
drive.tag?.ifHas(FILTER_PATH, CompoundTag::class.java, filter::deserializeNBT)
@JvmField return filter
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)
} }
@Suppress("unused") @Suppress("unused")
companion object { companion object {
const val MAX_FILTERS = 4 * 3
const val FILTER_PATH = "filter"
@SubscribeEvent @SubscribeEvent
fun onPickupEvent(event: EntityItemPickupEvent) { fun onPickupEvent(event: EntityItemPickupEvent) {
if (event.item.owner != null && event.item.owner != event.player.uuid && event.item.age < 200) { 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 { stack.getCapability(MatteryCapability.DRIVE).ifPresent {
val filter = drive.getFilterSettings(stack) val filter = drive.getFilterSettings(stack)
if (filter.matches(event.item.item)) { if (filter.match(event.item.item)) {
val copy = event.item.item.copy() val copy = event.item.item.copy()
val remaining = (it as ItemMatteryDrive).insertStack(event.item.item, false) val remaining = (it as ItemMatteryDrive).insertStack(event.item.item, false)

View File

@ -1,24 +1,23 @@
package ru.dbotthepony.mc.otm.menu package ru.dbotthepony.mc.otm.menu
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.SimpleContainer import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.energy.CapabilityEnergy 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.block.entity.DriveViewerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive 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
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem.FilterSettings
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView 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.registry.MMenus
import ru.dbotthepony.mc.otm.storage.ITEM_STORAGE
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
import ru.dbotthepony.mc.otm.storage.PoweredVirtualComponent import ru.dbotthepony.mc.otm.storage.PoweredVirtualComponent
import java.util.function.Supplier
class DriveViewerMenu @JvmOverloads constructor( class DriveViewerMenu @JvmOverloads constructor(
containerID: Int, containerID: Int,
@ -27,9 +26,10 @@ class DriveViewerMenu @JvmOverloads constructor(
) : MatteryPoweredMenu( ) : MatteryPoweredMenu(
MMenus.DRIVE_VIEWER, containerID, inventory, tile MMenus.DRIVE_VIEWER, containerID, inventory, tile
), INetworkedItemViewSupplier { ), INetworkedItemViewSupplier {
val view: NetworkedItemView val view = NetworkedItemView(inventory.player, this, tile == null)
private val powered: PoweredVirtualComponent<ItemStackWrapper>?
val driveSlot: MatterySlot val driveSlot: MatterySlot
private val powered: PoweredVirtualComponent<ItemStackWrapper>?
private var lastDrive: IMatteryDrive<ItemStackWrapper>? = null private var lastDrive: IMatteryDrive<ItemStackWrapper>? = null
override fun getNetworkedItemView() = view override fun getNetworkedItemView() = view
@ -43,8 +43,6 @@ class DriveViewerMenu @JvmOverloads constructor(
} }
} }
view = NetworkedItemView(inventory.player, this, tile == null)
if (tile != null) { if (tile != null) {
powered = PoweredVirtualComponent( powered = PoweredVirtualComponent(
ItemStackWrapper::class.java, ItemStackWrapper::class.java,
@ -60,6 +58,26 @@ class DriveViewerMenu @JvmOverloads constructor(
addInventorySlots() 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() { override fun broadcastChanges() {
super.broadcastChanges() super.broadcastChanges()
@ -70,21 +88,44 @@ class DriveViewerMenu @JvmOverloads constructor(
lastDrive = null lastDrive = null
if (!itemStack.isEmpty) { if (!itemStack.isEmpty) {
itemStack.getCapability(MatteryCapability.DRIVE).ifPresent { itemStack.getCapability(MatteryCapability.DRIVE).ifPresentK {
if (it.storageType === OverdriveThatMatters.INSTANCE.ITEM_STORAGE()) { if (it.storageType === ITEM_STORAGE) {
lastDrive = it as IMatteryDrive<ItemStackWrapper> lastDrive = it as IMatteryDrive<ItemStackWrapper>
} }
} }
} }
if (prev != lastDrive) { if (prev != lastDrive) {
if (prev != null) prev?.let(powered!!::remove)
powered!!.remove(prev)
view.clear() view.clear()
lastDrive?.let(powered!!::add)
if (lastDrive != null) if (lastDrive != null) {
powered!!.add(lastDrive!!) 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() view.network()
@ -102,10 +143,10 @@ class DriveViewerMenu @JvmOverloads constructor(
override fun removed(p_38940_: Player) { override fun removed(p_38940_: Player) {
super.removed(p_38940_) super.removed(p_38940_)
if (powered != null) if (lastDrive != null)
lastDrive?.removeListener(powered) powered?.remove(lastDrive!!)
view.clear() view.removed()
} }
override fun quickMoveStack(ply: Player, slot_index: Int): ItemStack { override fun quickMoveStack(ply: Player, slot_index: Int): ItemStack {
@ -135,107 +176,4 @@ class DriveViewerMenu @JvmOverloads constructor(
slot.setChanged() slot.setChanged()
return copy 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 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 { fun asClient(): BooleanPlayerInputWidget {
supplier = null supplier = null
clicker = { clicker = {

View File

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

View File

@ -36,6 +36,8 @@
"otm.gui.matter.name": "MtU", "otm.gui.matter.name": "MtU",
"otm.gui.filter.is_whitelist": "Is Whitelist", "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", "otm.gui.android_research": "Research Tree",
@ -88,10 +90,6 @@
"otm.filter.yes": "Yes", "otm.filter.yes": "Yes",
"otm.filter.no": "No", "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", "otm.matter_bottler.switch_mode": "Switch work mode",
"android_feature.overdrive_that_matters.air_bags": "Air Bags", "android_feature.overdrive_that_matters.air_bags": "Air Bags",