Make Exopack slot changes trigger advancements, and optimize them
This commit is contained in:
parent
7662c21f44
commit
f27f21e3de
@ -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_);
|
||||
}
|
||||
}
|
@ -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<CriterionTriggerInstance> {
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -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<Pair<Container, Iterator<Int>>>) : Co
|
||||
return true
|
||||
}
|
||||
|
||||
fun optimizedIterator(): Iterator<ItemStack> {
|
||||
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<Pair<Container, Iterator<Int>>>()
|
||||
|
@ -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<Update>()
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 <T, A, R> Iterator<T>.collect(collector: Collector<T, A, R>): R {
|
||||
return collector.finisher().apply(instance)
|
||||
}
|
||||
|
||||
fun <T> Iterator<T>.toList(): List<T> {
|
||||
val result = ArrayList<T>()
|
||||
result.addAll(this)
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T : Any> Iterator<T>.findFirst(): Optional<T> {
|
||||
if (hasNext()) {
|
||||
return Optional.of(next())
|
||||
|
@ -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<InventoryChangeTrigger.TriggerInstance> {
|
||||
private object BoundsStrategy : Strategy<MinMaxBounds.Ints?> {
|
||||
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<Any?> {
|
||||
override fun equals(a: Any?, b: Any?): Boolean {
|
||||
return a == b
|
||||
}
|
||||
|
||||
override fun hashCode(o: Any?): Int {
|
||||
return o.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
private fun interface Tester<T> {
|
||||
fun test(value: T, inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int): Boolean
|
||||
}
|
||||
|
||||
private fun interface Hint<T> {
|
||||
fun getHints(inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int): Collection<T>?
|
||||
}
|
||||
|
||||
private class Node<T>(
|
||||
val strategy: Strategy<in T?>,
|
||||
private val getter: InventoryChangeTrigger.TriggerInstance.() -> Collection<T>,
|
||||
val test: Tester<T>,
|
||||
val hint: Hint<T>? = null
|
||||
) {
|
||||
fun getValues(instance: InventoryChangeTrigger.TriggerInstance): Set<T> {
|
||||
val result = ObjectArraySet<T>()
|
||||
result.addAll(getter.invoke(instance))
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private val nodes = ArrayList<Node<*>>()
|
||||
|
||||
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<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>()
|
||||
private val tree = Object2ObjectOpenCustomHashMap<Any?, Any>(nodes.first().strategy as Strategy<in Any?>)
|
||||
|
||||
private fun search(instance: InventoryChangeTrigger.TriggerInstance, tree: MutableMap<Any?, Any>, nodeId: Int): Collection<MutableSet<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>> {
|
||||
val node = nodes[nodeId]
|
||||
|
||||
if (nodeId + 1 != nodes.size) {
|
||||
val result = ArrayList<MutableSet<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>>()
|
||||
|
||||
for (v in node.getValues(instance)) {
|
||||
result.addAll(
|
||||
search(
|
||||
instance,
|
||||
tree.computeIfAbsent(v, Object2ObjectFunction { Object2ObjectOpenCustomHashMap<Any, Any>(nodes[nodeId + 1].strategy as Strategy<in Any?>) }) as MutableMap<Any?, Any>,
|
||||
nodeId + 1))
|
||||
}
|
||||
|
||||
return result
|
||||
} else {
|
||||
val result = ArrayList<MutableSet<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>>()
|
||||
|
||||
for (v in node.getValues(instance)) {
|
||||
result.add(tree.computeIfAbsent(v, Object2ObjectFunction { ObjectOpenHashSet<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>() }) as MutableSet<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
fun add(listener: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) {
|
||||
if (set.add(listener)) {
|
||||
search(listener.triggerInstance, tree, 0).forEach { it.add(listener) }
|
||||
}
|
||||
}
|
||||
|
||||
fun remove(listener: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) {
|
||||
if (set.remove(listener)) {
|
||||
search(listener.triggerInstance, tree, 0).forEach { it.remove(listener) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun addNull(input: Collection<Any?>): Collection<Any?> {
|
||||
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<Any?, Any>, nodeId: Int, set: MutableSet<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>) {
|
||||
val node = nodes[nodeId] as Node<Any?>
|
||||
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<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>) {
|
||||
// переделываем 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<Any?, Any>, nodeId + 1, set)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun trigger(inventory: Container, item: ItemStack, slotsFull: Int, slotsEmpty: Int, slotsOccupied: Int) {
|
||||
val matches = ObjectOpenHashSet<CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>>()
|
||||
|
||||
trigger(inventory, item, slotsFull, slotsEmpty, slotsOccupied, tree, 0, matches)
|
||||
|
||||
for (l in matches) {
|
||||
l.run(advancements)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val listeners = Reference2ObjectOpenHashMap<PlayerAdvancements, ListenerTree>()
|
||||
|
||||
override fun getId(): ResourceLocation {
|
||||
return CriteriaTriggers.INVENTORY_CHANGED.id
|
||||
}
|
||||
|
||||
override fun addPlayerListener(advancements: PlayerAdvancements, instance: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) {
|
||||
listeners.computeIfAbsent(advancements, Reference2ObjectFunction { ListenerTree(it as PlayerAdvancements) }).add(instance)
|
||||
}
|
||||
|
||||
override fun removePlayerListener(advancements: PlayerAdvancements, instance: CriterionTrigger.Listener<InventoryChangeTrigger.TriggerInstance>) {
|
||||
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)
|
||||
}
|
||||
}
|
@ -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_
|
||||
|
@ -13,6 +13,8 @@
|
||||
"MixinAnvilBlock",
|
||||
"MixinInventory",
|
||||
"MixinAbstractHurtingProjectile",
|
||||
"SimpleCriterionTriggerMixin",
|
||||
"InventoryChangeTriggerMixin",
|
||||
"MixinPlayer"
|
||||
],
|
||||
"client": [
|
||||
|
Loading…
Reference in New Issue
Block a user