From a2263c57258cf90388bb936217b00513613a0656 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:11:39 +0700 Subject: [PATCH] Update MatteryPlayer to use Enhanced containers instead of Mattery containers --- .../mc/otm/container/IAutomatedContainer.kt | 4 +- .../mc/otm/container/ISlottedContainer.kt | 12 ++- .../otm/container/slotted/SlottedContainer.kt | 4 +- .../mc/otm/player/ExopackContainer.kt | 21 ++++ .../mc/otm/player/IPlayerInventorySlot.kt | 7 ++ .../mc/otm/player/MatteryPlayer.kt | 100 +++++++----------- .../mc/otm/player/PlayerInventoryWrapper.kt | 73 +++++++++++++ 7 files changed, 156 insertions(+), 65 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/player/IPlayerInventorySlot.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt index 2a703741f..f143f30a2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt @@ -10,9 +10,7 @@ import net.neoforged.neoforge.items.IItemHandlerModifiable * Reinforced [ISlottedContainer] which slots are [IAutomatedContainerSlot]s, which * subsequently allow this container to implement [IItemHandler] */ -interface IAutomatedContainer : ISlottedContainer, IItemHandlerModifiable { - override fun containerSlot(slot: Int): IAutomatedContainerSlot - +interface IAutomatedContainer : ISlottedContainer, IItemHandlerModifiable { override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { return containerSlot(slot).canAutomationPlaceItem(itemStack) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index 8e2442836..020c2d6d3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -8,7 +8,17 @@ import ru.dbotthepony.kommons.collect.any /** * Skeletal implementation for containers which revolve around [IContainerSlot] */ -interface ISlottedContainer : IEnhancedContainer { +interface ISlottedContainer : IEnhancedContainer { + override fun containerSlot(slot: Int): S + + override fun slotIterator(): Iterator { + return super.slotIterator() as Iterator + } + + override fun nonEmptySlotIterator(): Iterator { + return super.nonEmptySlotIterator() as Iterator + } + override fun setChanged(slot: Int) { containerSlot(slot).setChanged() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt index ca04ebf0b..1b5a66420 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt @@ -40,7 +40,7 @@ class SlottedContainer( slots: Collection>, private val stillValid: Predicate, private val globalChangeListeners: Array -) : IAutomatedContainer, INBTSerializable { +) : IAutomatedContainer, INBTSerializable { interface ISlotGroup : List { /** * @see IAutomatedContainer.addItem @@ -140,7 +140,7 @@ class SlottedContainer( } } - override fun containerSlot(slot: Int): IAutomatedContainerSlot { + override fun containerSlot(slot: Int): ContainerSlot { return slots[slot] } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt new file mode 100644 index 000000000..eb71b2c80 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt @@ -0,0 +1,21 @@ +package ru.dbotthepony.mc.otm.player + +import net.minecraft.world.item.Item +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.container.IContainerSlot + +class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer(size) { + private inner class Slot(slot: Int) : IContainerSlot.Simple(slot, this@ExopackContainer), IPlayerInventorySlot { + override var shouldCharge: Boolean + get() = (PlayerInventoryWrapper.SLOTS + slot) in player.slotsChargeFlag + set(value) { if (value) player.slotsChargeFlag.add(PlayerInventoryWrapper.SLOTS + slot) else player.slotsChargeFlag.remove(PlayerInventoryWrapper.SLOTS + slot) } + + override var filter: Item? + get() = player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] + set(value) { if (value == null) player.slotFilters.remove(PlayerInventoryWrapper.SLOTS + slot) else player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] = value } + } + + override fun containerSlot(slot: Int): IPlayerInventorySlot { + return Slot(slot) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/IPlayerInventorySlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/IPlayerInventorySlot.kt new file mode 100644 index 000000000..6719c2fb2 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/IPlayerInventorySlot.kt @@ -0,0 +1,7 @@ +package ru.dbotthepony.mc.otm.player + +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot + +interface IPlayerInventorySlot : IFilteredContainerSlot { + var shouldCharge: Boolean +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index 4dd651770..48c6b88e3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -2,6 +2,9 @@ package ru.dbotthepony.mc.otm.player import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.PoseStack +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import it.unimi.dsi.fastutil.ints.IntSet import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap @@ -12,6 +15,7 @@ import net.minecraft.core.HolderLookup import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag +import net.minecraft.nbt.NbtOps import net.minecraft.nbt.StringTag import net.minecraft.network.chat.Component import net.minecraft.network.protocol.common.custom.CustomPacketPayload @@ -76,12 +80,16 @@ import ru.dbotthepony.mc.otm.config.PlayerConfig import ru.dbotthepony.mc.otm.config.ExopackConfig import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.DynamicallyProxiedContainer +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IContainer import ru.dbotthepony.mc.otm.container.IContainerSlot +import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.IMatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.get +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.util.slotIterator import ru.dbotthepony.mc.otm.container.vanishCursedItems import ru.dbotthepony.mc.otm.core.* @@ -95,6 +103,7 @@ import ru.dbotthepony.mc.otm.core.nbt.getStringList import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.util.Savetables import ru.dbotthepony.mc.otm.core.util.TickList +import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu import ru.dbotthepony.mc.otm.menu.IItemStackSortingSettings import ru.dbotthepony.mc.otm.network.* @@ -158,10 +167,10 @@ class MatteryPlayer(val ply: Player) { val level: Level get() = capability.ply.level() } - private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) { - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { + private inner class PlayerMatteryContainer(size: Int) : EnhancedContainer(size) { + override fun notifySlotChanged(slot: Int, old: ItemStack) { if (ply is ServerPlayer) { - val item = new.copy() + val item = this[slot].copy() tickList.once { MatteryInventoryChangeTrigger.trigger(ply, combinedInventory, item) @@ -249,22 +258,20 @@ class MatteryPlayer(val ply: Player) { * If you want to properly extend Exopack suit capacity, add your value into this map */ val exopackSlotModifier = UUIDIntModifiersMap(observer = observer@{ - if (it < 0) { - exopackContainer = PlayerMatteryContainer(0) - } else { - exopackContainer = PlayerMatteryContainer(it) - } + exopackContainer = ExopackContainer(it.coerceAtLeast(0), this) }, backingMap = this.exopackSlotModifierMap.delegate) - val regularSlotFilters = immutableList(Inventory.INVENTORY_SIZE) { - syncher.add(null, StreamCodecs.ITEM_TYPE.nullable()) - } - val slotsChargeFlag = syncher.set( backing = ListenableSet(IntAVLTreeSet()), codec = StreamCodecs.VAR_INT, ).delegate + val slotFilters = syncher.map( + backing = ListenableMap(Int2ObjectOpenHashMap()), + keyCodec = StreamCodecs.VAR_INT, + valueCodec = StreamCodecs.ITEM_TYPE + ).delegate + private fun slotChargeToDefault() { // броня slotsChargeFlag.add(36) @@ -277,15 +284,12 @@ class MatteryPlayer(val ply: Player) { slotChargeToDefault() } - private var exopackContainerSynchedFilters: List = listOf() - /** * Exopack container, which actually store items inside Exopack */ - var exopackContainer: MatteryContainer = PlayerMatteryContainer(0) + var exopackContainer: ExopackContainer = ExopackContainer(0, this) private set(value) { _exoPackMenu = null - exopackContainerSynchedFilters.forEach { it.close() } @Suppress("SENSELESS_COMPARISON") // false positive - fields of player can easily be nulls, despite annotations saying otherwise if (ply.containerMenu != null && (ply !is ServerPlayer || ply.connection != null)) { @@ -300,7 +304,6 @@ class MatteryPlayer(val ply: Player) { } value.deserializeNBT(ply.level().registryAccess(), field.serializeNBT(ply.level().registryAccess())) - exopackContainerSynchedFilters = value.synchableFilters.map { syncher.add0(it) } field = value _combinedInventory = null @@ -312,34 +315,9 @@ class MatteryPlayer(val ply: Player) { private var _combinedInventory2: CombinedContainer? = null private var _combinedInventory3: CombinedContainer? = null - val wrappedInventory: IMatteryContainer = object : IMatteryContainer, IContainer by DynamicallyProxiedContainer(ply::getInventory) { - override fun getSlotFilter(slot: Int): Item? { - return regularSlotFilters.getOrNull(slot)?.get() - } + val wrappedInventory = PlayerInventoryWrapper(this) - override fun setSlotFilter(slot: Int, filter: Item?): Boolean { - regularSlotFilters.getOrNull(slot)?.accept(filter) - return true - } - - override fun setChanged(slot: Int) { - ply.inventory.setChanged() - } - - override fun clearSlotFilters() { - regularSlotFilters.forEach { it.accept(null) } - } - - override fun containerSlot(slot: Int): IFilteredContainerSlot { - return object : IContainerSlot.Simple(slot, this), IFilteredContainerSlot { - override var filter: Item? - get() = regularSlotFilters.getOrNull(slot)?.get() - set(value) { regularSlotFilters.getOrNull(slot)?.accept(value) } - } - } - } - - val wrappedItemInventory: IMatteryContainer = object : IMatteryContainer by wrappedInventory { + val wrappedItemInventory: IEnhancedContainer = object : IEnhancedContainer by wrappedInventory { override fun getContainerSize(): Int { return 36 } @@ -955,11 +933,8 @@ class MatteryPlayer(val ply: Player) { } } - tag["regularSlotFilters"] = ListTag().also { - for (filter in regularSlotFilters) { - it.add(StringTag.valueOf(filter.value?.registryName?.toString() ?: "")) - } - } + tag["slotFilters"] = filtersCodec.encodeStart(registry.createSerializationContext(NbtOps.INSTANCE), slotFilters.entries.map { it.key to it.value }) + .getOrThrow { IllegalStateException("Unable to serialize slot filters: $it") } tag.putIntArray("slotsChargeFlag", slotsChargeFlag.toIntArray()) return tag @@ -977,18 +952,16 @@ class MatteryPlayer(val ply: Player) { ExopackSlotsExpandedTrigger.trigger(ply, 0, exopackContainer.containerSize) } - for (filter in regularSlotFilters) { - filter.value = null - } - + slotFilters.clear() slotsChargeFlag.clear() - val regularSlotFilters = tag.getStringList("regularSlotFilters") - - for (i in 0 until regularSlotFilters.size.coerceAtMost(this.regularSlotFilters.size)) { - val path = regularSlotFilters[i].asString - if (path == "") continue - this.regularSlotFilters[i].value = BuiltInRegistries.ITEM.get(ResourceLocation.tryParse(path) ?: continue) + if ("slotFilters" in tag) { + filtersCodec.decode(registry.createSerializationContext(NbtOps.INSTANCE), tag["slotFilters"]) + .ifError { LOGGER.error("Unable to deserialize slot filters: ${it.message()}") } + .resultOrPartial() + .ifPresent { + it.first.forEach { (a, b) -> slotFilters[a] = b } + } } if ("slotsChargeFlag" in tag) { @@ -1341,6 +1314,15 @@ class MatteryPlayer(val ply: Player) { @Suppress("unused") companion object { + private val filtersCodec: Codec>> = Codec.list( + RecordCodecBuilder.create { + it.group( + Codec.INT.minRange(0).fieldOf("slot").forGetter { it.first }, + BuiltInRegistries.ITEM.byNameCodec().fieldOf("filter").forGetter { it.second } + ).apply(it, ::Pair) + } + ) + private val offhandSlotRange = IntSet.of(40) init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt new file mode 100644 index 000000000..35b15d786 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt @@ -0,0 +1,73 @@ +package ru.dbotthepony.mc.otm.player + +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.container.ISlottedContainer +import ru.dbotthepony.mc.otm.container.get +import ru.dbotthepony.mc.otm.container.set + +class PlayerInventoryWrapper(val player: MatteryPlayer) : ISlottedContainer { + val inventory: Inventory + get() = player.ply.inventory + + private inner class Slot(val slot: Int) : IPlayerInventorySlot { + override fun setChanged() { + inventory.setChanged() + } + + override var filter: Item? + get() = player.slotFilters[slot] + set(value) { if (value == null) player.slotFilters.remove(slot) else player.slotFilters[slot] = value } + override var shouldCharge: Boolean + get() = slot in player.slotsChargeFlag + set(value) { if (value) player.slotsChargeFlag.add(slot) else player.slotsChargeFlag.remove(slot) } + override var item: ItemStack + get() = inventory[slot] + set(value) { inventory[slot] = value } + override val maxStackSize: Int + get() = inventory.maxStackSize + + override fun maxStackSize(item: ItemStack): Int { + return inventory.getMaxStackSize(item) + } + + override fun remove(): ItemStack { + return inventory.removeItemNoUpdate(slot) + } + + override fun remove(count: Int): ItemStack { + return inventory.removeItem(slot, count) + } + } + + private val slots = Array(SLOTS) { Slot(it) } + + override val hasFilterableSlots: Boolean + get() = true + + override fun containerSlot(slot: Int): IPlayerInventorySlot { + return slots[slot] + } + + override fun clearContent() { + slots.forEach { it.remove() } + } + + override fun setChanged() { + inventory.setChanged() + } + + override fun getContainerSize(): Int { + return slots.size + } + + override fun stillValid(player: Player): Boolean { + return inventory.stillValid(player) + } + + companion object { + const val SLOTS = 41 + } +}