diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/InventoryChangeTriggerMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/InventoryChangeTriggerMixin.java new file mode 100644 index 000000000..6aea160bd --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/InventoryChangeTriggerMixin.java @@ -0,0 +1,22 @@ +package ru.dbotthepony.mc.otm.mixin; + +import net.minecraft.advancements.critereon.InventoryChangeTrigger; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.triggers.MatteryInventoryChangeTrigger; + +@Mixin(InventoryChangeTrigger.class) +public abstract class InventoryChangeTriggerMixin { + @Overwrite + public void trigger(ServerPlayer p_43150_, Inventory p_43151_, ItemStack p_43152_) { + MatteryInventoryChangeTrigger.INSTANCE.trigger(p_43150_, p_43151_, p_43152_); + } + + @Overwrite + private void trigger(ServerPlayer p_43154_, Inventory p_43155_, ItemStack p_43156_, int p_43157_, int p_43158_, int p_43159_) { + MatteryInventoryChangeTrigger.INSTANCE.trigger(p_43154_, p_43155_, p_43156_, p_43157_, p_43158_, p_43159_); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/SimpleCriterionTriggerMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/SimpleCriterionTriggerMixin.java new file mode 100644 index 000000000..d5d3e701f --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/SimpleCriterionTriggerMixin.java @@ -0,0 +1,54 @@ +package ru.dbotthepony.mc.otm.mixin; + +import net.minecraft.advancements.CriterionTrigger; +import net.minecraft.advancements.CriterionTriggerInstance; +import net.minecraft.advancements.critereon.InventoryChangeTrigger; +import net.minecraft.advancements.critereon.SimpleCriterionTrigger; +import net.minecraft.server.PlayerAdvancements; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import ru.dbotthepony.mc.otm.triggers.MatteryInventoryChangeTrigger; + +// i tried to mixin into InventoryChangeTrigger with extends SimpleCriterionTrigger and @Overwrite+@Override +// while also defining SimpleCriterionTrigger methods non final in accesstransfoer +// it didn't work. +@Mixin(SimpleCriterionTrigger.class) +public abstract class SimpleCriterionTriggerMixin implements CriterionTrigger { + @Inject( + method = "removePlayerListener(Lnet/minecraft/server/PlayerAdvancements;Lnet/minecraft/advancements/CriterionTrigger$Listener;)V", + at = @At("HEAD"), + cancellable = true + ) + public void removePlayerListener(PlayerAdvancements p_66254_, CriterionTrigger.Listener p_66255_, CallbackInfo info) { + if (((Object) this) instanceof InventoryChangeTrigger) { + MatteryInventoryChangeTrigger.INSTANCE.removePlayerListener(p_66254_, p_66255_); + info.cancel(); + } + } + + @Inject( + method = "addPlayerListener(Lnet/minecraft/server/PlayerAdvancements;Lnet/minecraft/advancements/CriterionTrigger$Listener;)V", + at = @At("HEAD"), + cancellable = true + ) + public void addPlayerListener(PlayerAdvancements p_66254_, CriterionTrigger.Listener p_66255_, CallbackInfo info) { + if (((Object) this) instanceof InventoryChangeTrigger) { + MatteryInventoryChangeTrigger.INSTANCE.addPlayerListener(p_66254_, p_66255_); + info.cancel(); + } + } + + @Inject( + method = "removePlayerListeners(Lnet/minecraft/server/PlayerAdvancements;)V", + at = @At("HEAD"), + cancellable = true + ) + public void removePlayerListeners(PlayerAdvancements p_66254_, CallbackInfo info) { + if (((Object) this) instanceof InventoryChangeTrigger) { + MatteryInventoryChangeTrigger.INSTANCE.removePlayerListeners(p_66254_); + info.cancel(); + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt index 8d8431c6d..51c08d53c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt @@ -79,6 +79,7 @@ import ru.dbotthepony.mc.otm.capability.energy.receiveEnergyExact import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.config.AndroidConfig import ru.dbotthepony.mc.otm.config.ExopackConfig +import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.iterator @@ -122,6 +123,7 @@ import ru.dbotthepony.mc.otm.triggers.ExopackGainedEnderAccessTrigger import ru.dbotthepony.mc.otm.triggers.ExopackGainedSmeltingTrigger import ru.dbotthepony.mc.otm.triggers.ExopackObtainedTrigger import ru.dbotthepony.mc.otm.triggers.ExopackSlotsExpandedTrigger +import ru.dbotthepony.mc.otm.triggers.MatteryInventoryChangeTrigger import java.util.* import java.util.stream.Stream import kotlin.collections.ArrayDeque @@ -170,12 +172,13 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - super.setChanged(slot, new, old) - // TODO: Minecraft has hard-coded inventory triggers to Inventory class - // when nothing use Inventory class directly. + if (ply is ServerPlayer) { + val item = new.copy() - // Why? - // CriteriaTriggers.INVENTORY_CHANGED.trigger(this, this.getInventory(), p_143468_) + tickList.once { + MatteryInventoryChangeTrigger.trigger(ply, combinedInventory, item) + } + } } } @@ -300,6 +303,18 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial value.deserializeNBT(field.serializeNBT()) value.addFilterSynchronizer(synchronizer) field = value + + _combinedInventory = CombinedContainer(ply.inventory, exopackContainer) + } + + private var _combinedInventory: CombinedContainer? = null + + val combinedInventory: CombinedContainer + get() { + if (_combinedInventory == null) + _combinedInventory = CombinedContainer(ply.inventory, exopackContainer) + + return _combinedInventory!! } /** @@ -1065,6 +1080,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial ticksIExist++ + tickList.tick() + if (willBecomeAndroid) { if (ply.isSleeping && ply.sleepTimer > SLEEP_TICKS_LIMIT) { becomeAndroid() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt index c37b8e51a..90c253d10 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt @@ -12,6 +12,10 @@ import net.minecraft.world.Container import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.core.GetterSetter +import ru.dbotthepony.mc.otm.core.collect.filter +import ru.dbotthepony.mc.otm.core.collect.flatMap +import ru.dbotthepony.mc.otm.core.collect.map +import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.stream import java.util.LinkedList import java.util.stream.Stream @@ -162,6 +166,13 @@ class CombinedContainer(containers: Stream>>) : Co return true } + fun optimizedIterator(): Iterator { + return listOf( + fullCoverage.iterator().flatMap { it.iterator() }, + notFullCoverage.values.iterator().flatMap { it.iterator() }.map { it.item }.filter { it.isNotEmpty } + ).iterator().flatMap { it } + } + class Builder { private var built = false private val values = LinkedList>>() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt index e03d238fd..95d1624d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt @@ -47,6 +47,9 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I private val nonEmptyFlags = BitSet() private var nonEmptyIndices = IntArrayList() private var indicesReferenced = false + private data class Update(val slot: Int, val new: ItemStack, val old: ItemStack) + private val queuedUpdates = ArrayList() + private var queueUpdates = false private fun cowIndices() { if (indicesReferenced) { @@ -224,6 +227,22 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I } } + private fun internalSetChanged(slot: Int, new: ItemStack, old: ItemStack) { + if (queueUpdates) { + queuedUpdates.add(Update(slot, new, old)) + } else { + setChanged(slot, new, old) + } + } + + private fun runUpdates() { + for ((slot, new, old) in queuedUpdates) { + setChanged(slot, new, old) + } + + queuedUpdates.clear() + } + protected open fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { watcher.run() } @@ -297,7 +316,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I slotStack.count = newCount trackedSlots[slot] = slotStack.copy() changeset++ - setChanged(slot, slotStack, old) + internalSetChanged(slot, slotStack, old) if (popTime != null) { slotStack.popTime = popTime @@ -326,7 +345,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I trackedSlots[slot] = copyToPut.copy() updateEmptyFlag(slot) changeset++ - setChanged(slot, copyToPut, ItemStack.EMPTY) + internalSetChanged(slot, copyToPut, ItemStack.EMPTY) if (popTime != null) { copyToPut.popTime = popTime @@ -430,7 +449,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I trackedSlots[slot] = slots[slot].copy() changeset++ updateEmptyFlag(slot) - setChanged(slot, if (slots[slot].isEmpty) ItemStack.EMPTY else slots[slot], old) + internalSetChanged(slot, if (slots[slot].isEmpty) ItemStack.EMPTY else slots[slot], old) return split } @@ -458,12 +477,21 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I updateEmptyFlag(slot) changeset++ - setChanged(slot, stack, old) + internalSetChanged(slot, stack, old) } final override fun setChanged() { - for (slot in 0 until size) { - setChanged(slot) + queueUpdates = true + + try { + for (slot in 0 until size) { + setChanged(slot) + } + + runUpdates() + } finally { + queuedUpdates.clear() + queueUpdates = false } } @@ -472,7 +500,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I trackedSlots[slot] = slots[slot].copy() updateEmptyFlag(slot) changeset++ - setChanged(slot, slots[slot], trackedSlots[slot]) + internalSetChanged(slot, slots[slot], trackedSlots[slot]) // mojang соси))0)0))0)))))0) } } @@ -507,7 +535,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I if (!slots[slot].isEmpty) { val old = slots[slot] slots[slot] = ItemStack.EMPTY - setChanged(slot, ItemStack.EMPTY, old) + internalSetChanged(slot, ItemStack.EMPTY, old) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterator.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterator.kt index 1ca57f6a1..b098fa0c5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterator.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterator.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.core.collect +import ru.dbotthepony.mc.otm.core.addAll import java.util.Optional import java.util.function.BinaryOperator import java.util.function.Predicate @@ -348,6 +349,12 @@ fun Iterator.collect(collector: Collector): R { return collector.finisher().apply(instance) } +fun Iterator.toList(): List { + val result = ArrayList() + result.addAll(this) + return result +} + fun Iterator.findFirst(): Optional { if (hasNext()) { return Optional.of(next()) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/MatteryInventoryChangeTrigger.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/MatteryInventoryChangeTrigger.kt new file mode 100644 index 000000000..fa03d8913 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/MatteryInventoryChangeTrigger.kt @@ -0,0 +1,269 @@ +package ru.dbotthepony.mc.otm.triggers + +import com.google.gson.JsonObject +import it.unimi.dsi.fastutil.Hash.Strategy +import it.unimi.dsi.fastutil.objects.Object2ObjectFunction +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.ObjectArraySet +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet +import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction +import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap +import net.minecraft.advancements.CriteriaTriggers +import net.minecraft.advancements.CriterionTrigger +import net.minecraft.advancements.critereon.DeserializationContext +import net.minecraft.advancements.critereon.InventoryChangeTrigger +import net.minecraft.advancements.critereon.MinMaxBounds +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.PlayerAdvancements +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.Container +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.capability.matteryPlayer +import ru.dbotthepony.mc.otm.container.CombinedContainer +import ru.dbotthepony.mc.otm.container.get +import ru.dbotthepony.mc.otm.container.iterator +import ru.dbotthepony.mc.otm.core.collect.flatMap +import ru.dbotthepony.mc.otm.core.collect.toList +import ru.dbotthepony.mc.otm.core.isNotEmpty +import java.util.stream.Collectors + +/** + * This object detours all necessary InventoryChangeTrigger methods + * + * Reason behind this is to support arbitrary containers (not just [Inventory], done for Exopack) and to improve performance by using search tree + */ +object MatteryInventoryChangeTrigger : CriterionTrigger { + private object BoundsStrategy : Strategy { + override fun equals(a: MinMaxBounds.Ints?, b: MinMaxBounds.Ints?): Boolean { + return a?.min == b?.min && a?.max == b?.max + } + + override fun hashCode(o: MinMaxBounds.Ints?): Int { + return o?.let { Integer.rotateLeft(it.min.hashCode(), 16) xor it.max.hashCode() } ?: 0 + } + } + + private object DefaultStrategy : Strategy { + override fun equals(a: Any?, b: Any?): Boolean { + return a == b + } + + override fun hashCode(o: Any?): Int { + return o.hashCode() + } + } + + private fun interface Tester { + fun test(value: T, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int): Boolean + } + + private fun interface Hint { + fun getHints(inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int): Collection? + } + + private class Node( + val strategy: Strategy, + private val getter: InventoryChangeTrigger.TriggerInstance.() -> Collection, + val test: Tester, + val hint: Hint? = null + ) { + fun getValues(instance: InventoryChangeTrigger.TriggerInstance): Set { + val result = ObjectArraySet() + result.addAll(getter.invoke(instance)) + return result + } + } + + private val nodes = ArrayList>() + + init { + nodes.add(Node(BoundsStrategy, { listOf(slotsOccupied) }, { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v.matches(slotsOccupied) })) + nodes.add(Node(BoundsStrategy, { listOf(slotsFull) }, { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v.matches(slotsFull) })) + nodes.add(Node(BoundsStrategy, { listOf(slotsEmpty) }, { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v.matches(slotsEmpty) })) + + nodes.add(Node( + DefaultStrategy, + { predicates.iterator().flatMap { (it.items ?: listOf(null)).iterator() }.toList() }, + { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v == null || item.item == v }, + { inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> mutableListOf(item.item) })) + + nodes.add(Node( + DefaultStrategy, + { predicates.map { it.tag } }, + { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v == null || item.`is`(v) }, + { inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> item.tags.collect(Collectors.toCollection(::ArrayList)) })) + + nodes.add(Node(BoundsStrategy, { predicates.map { it.count } }, { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v.matches(item.count) })) + + nodes.add(Node( + BoundsStrategy, + { predicates.map { it.durability } }, + { v, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int -> v.isAny || item.isDamageableItem && v.matches(item.maxDamage - item.damageValue) })) + } + + private class ListenerTree(private val advancements: PlayerAdvancements) { + private val set = ObjectOpenHashSet>() + private val tree = Object2ObjectOpenCustomHashMap(nodes.first().strategy as Strategy) + + private fun search(instance: InventoryChangeTrigger.TriggerInstance, tree: MutableMap, nodeId: Int): Collection>> { + val node = nodes[nodeId] + + if (nodeId + 1 != nodes.size) { + val result = ArrayList>>() + + for (v in node.getValues(instance)) { + result.addAll( + search( + instance, + tree.computeIfAbsent(v, Object2ObjectFunction { Object2ObjectOpenCustomHashMap(nodes[nodeId + 1].strategy as Strategy) }) as MutableMap, + nodeId + 1)) + } + + return result + } else { + val result = ArrayList>>() + + for (v in node.getValues(instance)) { + result.add(tree.computeIfAbsent(v, Object2ObjectFunction { ObjectOpenHashSet>() }) as MutableSet>) + } + + return result + } + } + + fun add(listener: CriterionTrigger.Listener) { + if (set.add(listener)) { + search(listener.triggerInstance, tree, 0).forEach { it.add(listener) } + } + } + + fun remove(listener: CriterionTrigger.Listener) { + if (set.remove(listener)) { + search(listener.triggerInstance, tree, 0).forEach { it.remove(listener) } + } + } + + private fun addNull(input: Collection): Collection { + return if (null in input) + input + else if (input is ArrayList) { + input.add(null) + input + } else { + ArrayList(input).also { it.add(null) } + } + } + + private fun trigger(inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int, tree: MutableMap, nodeId: Int, set: MutableSet>) { + val node = nodes[nodeId] as Node + val keys = node.hint?.getHints(inventory, item, slotsFull, slotsEmpty, slotsOccupied)?.let(::addNull) ?: tree.keys + + for (k in keys) { + val v = tree[k] ?: continue + + if (node.test.test(k, inventory, item, slotsFull, slotsEmpty, slotsOccupied)) { + if (nodeId + 1 == nodes.size) { + for (l in v as Set>) { + // переделываем matches у InventoryTriggerInstance + with (l.triggerInstance) { + if ( + this.slotsFull.matches(slotsFull) && + this.slotsEmpty.matches(slotsEmpty) && + this.slotsOccupied.matches(slotsOccupied) + ) { + if (this.predicates.isEmpty() || this.predicates.size == 1 && item.isNotEmpty && this.predicates[0].matches(item)) { + set.add(l) + } else if (this.predicates.size > 1) { + val unsatisfied = ObjectArrayList(this.predicates) + unsatisfied.removeIf { it.matches(ItemStack.EMPTY) } + val iterator = if (inventory is CombinedContainer) inventory.optimizedIterator() else inventory.iterator() + + for (inventoryItem in iterator) { + unsatisfied.removeIf { it.matches(inventoryItem) } + if (unsatisfied.isEmpty) break + } + + if (unsatisfied.isEmpty) { + set.add(l) + } + } + } + } + } + } else { + trigger(inventory, item, slotsFull, slotsEmpty, slotsOccupied, v as MutableMap, nodeId + 1, set) + } + } + } + } + + fun trigger(inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int) { + val matches = ObjectOpenHashSet>() + + trigger(inventory, item, slotsFull, slotsEmpty, slotsOccupied, tree, 0, matches) + + for (l in matches) { + l.run(advancements) + } + } + } + + private val listeners = Reference2ObjectOpenHashMap() + + override fun getId(): ResourceLocation { + return CriteriaTriggers.INVENTORY_CHANGED.id + } + + override fun addPlayerListener(advancements: PlayerAdvancements, instance: CriterionTrigger.Listener) { + listeners.computeIfAbsent(advancements, Reference2ObjectFunction { ListenerTree(it as PlayerAdvancements) }).add(instance) + } + + override fun removePlayerListener(advancements: PlayerAdvancements, instance: CriterionTrigger.Listener) { + listeners[advancements]?.remove(instance) + } + + override fun removePlayerListeners(advancements: PlayerAdvancements) { + listeners.remove(advancements) + } + + override fun createInstance(data: JsonObject, context: DeserializationContext): InventoryChangeTrigger.TriggerInstance { + return CriteriaTriggers.INVENTORY_CHANGED.createInstance(data, context) + } + + // реплицирует ванильный метод + fun trigger(player: ServerPlayer, inventory: Container, item: ItemStack) { + if (inventory === player.inventory) { + val mattery = player.matteryPlayer + + if (mattery != null) { + return trigger(player, mattery.combinedInventory, item) + } + } + + var slotsFull = 0 + var slotsEmpty = 0 + var slotsOccupied = 0 + + for (slot in 0 until inventory.containerSize) { + val slotItem = inventory[slot] + + if (slotItem.isEmpty) + slotsEmpty++ + else { + slotsOccupied++ + + if (slotItem.count >= inventory.maxStackSize) + slotsFull++ + } + } + + trigger(player, inventory, item, slotsFull, slotsEmpty, slotsOccupied) + } + + // реплицирует ванильный метод + fun trigger(player: ServerPlayer, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int) { + listeners[player.advancements]?.trigger(inventory, item, slotsFull, slotsEmpty, slotsOccupied) + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 94ab2eea8..c7b31cf87 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -186,3 +186,20 @@ public net.minecraft.world.item.crafting.RecipeManager m_44054_(Lnet/minecraft/w public net.minecraft.world.entity.boss.wither.WitherBoss f_31432_ # TARGETING_CONDITIONS public-f net.minecraft.world.entity.boss.wither.WitherBoss f_31431_ # LIVING_ENTITY_SELECTOR public net.minecraft.world.entity.ai.targeting.TargetingConditions f_26879_ # selector + +public net.minecraft.advancements.critereon.InventoryChangeTrigger$TriggerInstance f_43179_ +public net.minecraft.advancements.critereon.InventoryChangeTrigger$TriggerInstance f_43178_ +public net.minecraft.advancements.critereon.InventoryChangeTrigger$TriggerInstance f_43177_ +public net.minecraft.advancements.critereon.InventoryChangeTrigger$TriggerInstance f_43176_ +#public-f net.minecraft.advancements.critereon.SimpleCriterionTrigger m_6467_(Lnet/minecraft/server/PlayerAdvancements;Lnet/minecraft/advancements/CriterionTrigger$Listener;)V # addPlayerListener +#public-f net.minecraft.advancements.critereon.SimpleCriterionTrigger m_6468_(Lnet/minecraft/server/PlayerAdvancements;Lnet/minecraft/advancements/CriterionTrigger$Listener;)V # removePlayerListener +#public-f net.minecraft.advancements.critereon.SimpleCriterionTrigger m_5656_(Lnet/minecraft/server/PlayerAdvancements;)V # removePlayerListeners + +public net.minecraft.advancements.critereon.ItemPredicate f_45031_ +public net.minecraft.advancements.critereon.ItemPredicate f_45032_ +public net.minecraft.advancements.critereon.ItemPredicate f_45033_ +public net.minecraft.advancements.critereon.ItemPredicate f_151427_ +public net.minecraft.advancements.critereon.ItemPredicate f_45036_ +public net.minecraft.advancements.critereon.ItemPredicate f_45035_ +public net.minecraft.advancements.critereon.ItemPredicate f_45034_ +public net.minecraft.advancements.critereon.ItemPredicate f_45029_ diff --git a/src/main/resources/overdrive_that_matters.mixins.json b/src/main/resources/overdrive_that_matters.mixins.json index 3d4d5f070..cc4920e9d 100644 --- a/src/main/resources/overdrive_that_matters.mixins.json +++ b/src/main/resources/overdrive_that_matters.mixins.json @@ -13,6 +13,8 @@ "MixinAnvilBlock", "MixinInventory", "MixinAbstractHurtingProjectile", + "SimpleCriterionTriggerMixin", + "InventoryChangeTriggerMixin", "MixinPlayer" ], "client": [