mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2026-01-06 15:51:31 +00:00
Current implementation of OP lock is not an appropriate solution to prevent plugins that contain backdoor or malicious code. There are many ways to bypass this check to manipulate the OP list or permissions. The best way to prevent this kind of grief is to get plugins from valid and trustworthy places.
425 lines
21 KiB
Diff
425 lines
21 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com>
|
|
Date: Tue, 9 Nov 2077 00:00:00 +0800
|
|
Subject: [PATCH] Lithium: equipment tracking
|
|
|
|
Should have special treatment to ArmorStand, since Paper introduced the configurable
|
|
ArmorStand no-tick, and still gives it ability to update equipment changes.
|
|
Thus added a bypass condition in LivingEntity#collectEquipmentChanges, always send
|
|
ArmorStand equipment changes even if the ArmorStand is no-tick
|
|
|
|
This patch is based on the following mixins:
|
|
* "net/caffeinemc/mods/lithium/mixin/util/item_component_and_count_tracking/PatchedDataComponentMapMixin.java"
|
|
* "net/caffeinemc/mods/lithium/mixin/util/item_component_and_count_tracking/ItemStackMixin.java"
|
|
* "net/caffeinemc/mods/lithium/mixin/entity/equipment_tracking/enchantment_ticking/LivingEntityMixin.java"
|
|
* "net/caffeinemc/mods/lithium/mixin/entity/equipment_tracking/equipment_changes/LivingEntityMixin.java"
|
|
* "net/caffeinemc/mods/lithium/mixin/entity/equipment_tracking/EntityEquipmentMixin.java"
|
|
* "net/caffeinemc/mods/lithium/common/util/change_tracking/ChangePublisher.java"
|
|
* "net/caffeinemc/mods/lithium/common/util/change_tracking/ChangeSubscriber.java"
|
|
By: 2No2Name <2No2Name@web.de>
|
|
As part of: Lithium (https://github.com/CaffeineMC/lithium)
|
|
Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html)
|
|
|
|
diff --git a/net/minecraft/core/component/PatchedDataComponentMap.java b/net/minecraft/core/component/PatchedDataComponentMap.java
|
|
index 3af6c1e2549ba3aeb60aa9d498a976be3680c0ee..57e0fc928cf97bac8d6ed3f2b746c2677a90c1b5 100644
|
|
--- a/net/minecraft/core/component/PatchedDataComponentMap.java
|
|
+++ b/net/minecraft/core/component/PatchedDataComponentMap.java
|
|
@@ -14,10 +14,11 @@ import java.util.Map.Entry;
|
|
import java.util.stream.Collectors;
|
|
import javax.annotation.Nullable;
|
|
|
|
-public final class PatchedDataComponentMap implements DataComponentMap {
|
|
+public final class PatchedDataComponentMap implements DataComponentMap, net.caffeinemc.mods.lithium.common.util.change_tracking.ChangePublisher<PatchedDataComponentMap> { // Leaf - Lithium - equipment tracking
|
|
private final DataComponentMap prototype;
|
|
private Reference2ObjectMap<DataComponentType<?>, Optional<?>> patch;
|
|
private boolean copyOnWrite;
|
|
+ private net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber<PatchedDataComponentMap> subscriber; // Leaf - Lithium - equipment tracking
|
|
|
|
public PatchedDataComponentMap(DataComponentMap prototype) {
|
|
this(prototype, Reference2ObjectMaps.emptyMap(), true);
|
|
@@ -135,6 +136,11 @@ public final class PatchedDataComponentMap implements DataComponentMap {
|
|
}
|
|
|
|
private void ensureMapOwnership() {
|
|
+ // Leaf start - Lithium - equipment tracking
|
|
+ if (this.subscriber != null) {
|
|
+ this.subscriber.lithium$notify(this, 0);
|
|
+ }
|
|
+ // Leaf end - Lithium - equipment tracking
|
|
if (this.copyOnWrite) {
|
|
this.patch = new Reference2ObjectArrayMap<>(this.patch);
|
|
this.copyOnWrite = false;
|
|
@@ -221,6 +227,22 @@ public final class PatchedDataComponentMap implements DataComponentMap {
|
|
return (DataComponentMap)(this.patch.isEmpty() ? this.prototype : this.copy());
|
|
}
|
|
|
|
+ // Leaf start - Lithium - equipment tracking
|
|
+ @Override
|
|
+ public void lithium$subscribe(net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber<PatchedDataComponentMap> subscriber, int subscriberData) {
|
|
+ if (subscriberData != 0) {
|
|
+ throw new UnsupportedOperationException("ComponentMapImpl does not support subscriber data");
|
|
+ }
|
|
+ this.subscriber = net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.combine(this.subscriber, 0, subscriber, 0);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int lithium$unsubscribe(net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber<PatchedDataComponentMap> subscriber) {
|
|
+ this.subscriber = net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.without(this.subscriber, subscriber);
|
|
+ return 0;
|
|
+ }
|
|
+ // Leaf end - Lithium - equipment tracking
|
|
+
|
|
@Override
|
|
public boolean equals(Object other) {
|
|
return this == other
|
|
diff --git a/net/minecraft/world/entity/EntityEquipment.java b/net/minecraft/world/entity/EntityEquipment.java
|
|
index 90814ad07a2686c5a274860395f5aca29cc3bf13..94c7ae9535a235abb8fddf0ca6578dfae2e675bb 100644
|
|
--- a/net/minecraft/world/entity/EntityEquipment.java
|
|
+++ b/net/minecraft/world/entity/EntityEquipment.java
|
|
@@ -7,7 +7,7 @@ import java.util.Objects;
|
|
import java.util.Map.Entry;
|
|
import net.minecraft.world.item.ItemStack;
|
|
|
|
-public class EntityEquipment {
|
|
+public class EntityEquipment implements net.caffeinemc.mods.lithium.common.entity.EquipmentInfo, net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.CountChangeSubscriber<ItemStack> { // Leaf - Lithium - equipment tracking
|
|
public static final Codec<EntityEquipment> CODEC = Codec.unboundedMap(EquipmentSlot.CODEC, ItemStack.CODEC).xmap(map -> {
|
|
EnumMap<EquipmentSlot, ItemStack> map1 = new EnumMap<>(EquipmentSlot.class);
|
|
map1.putAll((Map<? extends EquipmentSlot, ? extends ItemStack>)map);
|
|
@@ -18,6 +18,11 @@ public class EntityEquipment {
|
|
return map;
|
|
});
|
|
private final EnumMap<EquipmentSlot, ItemStack> items;
|
|
+ // Leaf start - Lithium - equipment tracking
|
|
+ boolean shouldTickEnchantments = false;
|
|
+ ItemStack recheckEnchantmentForStack = null;
|
|
+ boolean hasUnsentEquipmentChanges = true;
|
|
+ // Leaf end - Lithium - equipment tracking
|
|
|
|
private EntityEquipment(EnumMap<EquipmentSlot, ItemStack> items) {
|
|
this.items = items;
|
|
@@ -29,7 +34,11 @@ public class EntityEquipment {
|
|
|
|
public ItemStack set(EquipmentSlot slot, ItemStack stack) {
|
|
stack.getItem().verifyComponentsAfterLoad(stack);
|
|
- return Objects.requireNonNullElse(this.items.put(slot, stack), ItemStack.EMPTY);
|
|
+ // Leaf start - Lithium - equipment tracking
|
|
+ ItemStack oldStack = Objects.requireNonNullElse(this.items.put(slot, stack), ItemStack.EMPTY);
|
|
+ this.onEquipmentReplaced(oldStack, stack);
|
|
+ return oldStack;
|
|
+ // Leaf end - Lithium - equipment tracking
|
|
}
|
|
|
|
public ItemStack get(EquipmentSlot slot) {
|
|
@@ -56,8 +65,21 @@ public class EntityEquipment {
|
|
}
|
|
|
|
public void setAll(EntityEquipment equipment) {
|
|
+ this.onClear(); // Leaf - Lithium - equipment tracking
|
|
this.items.clear();
|
|
this.items.putAll(equipment.items);
|
|
+ // Leaf start - Lithium - equipment tracking
|
|
+ for (ItemStack newStack : this.items.values()) {
|
|
+ if (!newStack.isEmpty()) {
|
|
+ if (!this.shouldTickEnchantments) {
|
|
+ this.shouldTickEnchantments = stackHasTickableEnchantment(newStack);
|
|
+ }
|
|
+ if (!newStack.isEmpty()) {
|
|
+ newStack.lithium$subscribe(this, 0);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Leaf end - Lithium - equipment tracking
|
|
}
|
|
|
|
public void dropAll(LivingEntity entity) {
|
|
@@ -70,6 +92,7 @@ public class EntityEquipment {
|
|
|
|
public void clear() {
|
|
this.items.replaceAll((equipmentSlot, itemStack) -> ItemStack.EMPTY);
|
|
+ this.onClear(); // Leaf - Lithium - equipment tracking
|
|
}
|
|
|
|
// Paper start - EntityDeathEvent
|
|
@@ -78,4 +101,99 @@ public class EntityEquipment {
|
|
return this.items.containsKey(slot);
|
|
}
|
|
// Paper end - EntityDeathEvent
|
|
+
|
|
+ @Override
|
|
+ public boolean lithium$shouldTickEnchantments() {
|
|
+ this.processScheduledEnchantmentCheck(null);
|
|
+ return this.shouldTickEnchantments;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean lithium$hasUnsentEquipmentChanges() {
|
|
+ return this.hasUnsentEquipmentChanges;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void lithium$onEquipmentChangesSent() {
|
|
+ this.hasUnsentEquipmentChanges = false;
|
|
+ }
|
|
+
|
|
+ private void onClear() {
|
|
+ this.shouldTickEnchantments = false;
|
|
+ this.recheckEnchantmentForStack = null;
|
|
+ this.hasUnsentEquipmentChanges = true;
|
|
+
|
|
+ for (ItemStack oldStack : this.items.values()) {
|
|
+ if (!oldStack.isEmpty()) {
|
|
+ oldStack.lithium$unsubscribeWithData(this, 0);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void onEquipmentReplaced(ItemStack oldStack, ItemStack newStack) {
|
|
+ if (!this.shouldTickEnchantments) {
|
|
+ if (this.recheckEnchantmentForStack == oldStack) {
|
|
+ this.recheckEnchantmentForStack = null;
|
|
+ }
|
|
+ this.shouldTickEnchantments = stackHasTickableEnchantment(newStack);
|
|
+ }
|
|
+
|
|
+ this.hasUnsentEquipmentChanges = true;
|
|
+
|
|
+ if (!oldStack.isEmpty()) {
|
|
+ oldStack.lithium$unsubscribeWithData(this, 0);
|
|
+ }
|
|
+ if (!newStack.isEmpty()) {
|
|
+ newStack.lithium$subscribe(this, 0);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static boolean stackHasTickableEnchantment(ItemStack stack) {
|
|
+ if (!stack.isEmpty()) {
|
|
+ net.minecraft.world.item.enchantment.ItemEnchantments enchantments = stack.get(net.minecraft.core.component.DataComponents.ENCHANTMENTS);
|
|
+ if (enchantments != null && !enchantments.isEmpty()) {
|
|
+ for (net.minecraft.core.Holder<net.minecraft.world.item.enchantment.Enchantment> enchantmentEntry : enchantments.keySet()) {
|
|
+ if (!enchantmentEntry.value().getEffects(net.minecraft.world.item.enchantment.EnchantmentEffectComponents.TICK).isEmpty()) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void lithium$notify(@org.jetbrains.annotations.Nullable ItemStack publisher, int zero) {
|
|
+ this.hasUnsentEquipmentChanges = true;
|
|
+
|
|
+ if (!this.shouldTickEnchantments) {
|
|
+ this.processScheduledEnchantmentCheck(publisher);
|
|
+ this.scheduleEnchantmentCheck(publisher);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void scheduleEnchantmentCheck(@org.jetbrains.annotations.Nullable ItemStack toCheck) {
|
|
+ this.recheckEnchantmentForStack = toCheck;
|
|
+ }
|
|
+
|
|
+ private void processScheduledEnchantmentCheck(@org.jetbrains.annotations.Nullable ItemStack ignoredStack) {
|
|
+ if (this.recheckEnchantmentForStack != null && this.recheckEnchantmentForStack != ignoredStack) {
|
|
+ this.shouldTickEnchantments = stackHasTickableEnchantment(this.recheckEnchantmentForStack);
|
|
+ this.recheckEnchantmentForStack = null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void lithium$notifyCount(ItemStack publisher, int zero, int newCount) {
|
|
+ if (newCount == 0) {
|
|
+ publisher.lithium$unsubscribeWithData(this, zero);
|
|
+ }
|
|
+
|
|
+ this.onEquipmentReplaced(publisher, ItemStack.EMPTY);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void lithium$forceUnsubscribe(ItemStack publisher, int zero) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
}
|
|
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
|
index 4ab8e8b4301c4ab474c7c4362b40303627363e82..0e7ff8093241c9ac5c4a62edb2c250eeb0e80d3e 100644
|
|
--- a/net/minecraft/world/entity/LivingEntity.java
|
|
+++ b/net/minecraft/world/entity/LivingEntity.java
|
|
@@ -431,7 +431,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
|
this.getSleepingPos().ifPresent(this::setPosToBed);
|
|
}
|
|
|
|
- if (this.level() instanceof ServerLevel serverLevel) {
|
|
+ if ((this instanceof Player || this.equipment.lithium$shouldTickEnchantments()) && this.level() instanceof ServerLevel serverLevel) { // Leaf - Lithium - equipment tracking
|
|
EnchantmentHelper.tickEffects(serverLevel, this);
|
|
}
|
|
|
|
@@ -3458,6 +3458,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
|
public void detectEquipmentUpdates() {
|
|
Map<EquipmentSlot, ItemStack> map = this.collectEquipmentChanges();
|
|
if (map != null) {
|
|
+ if (!(this instanceof net.minecraft.world.entity.player.Player)) this.equipment.lithium$onEquipmentChangesSent(); // Leaf - Lithium - equipment tracking
|
|
this.handleHandSwap(map);
|
|
if (!map.isEmpty()) {
|
|
this.handleEquipmentChanges(map);
|
|
@@ -3467,6 +3468,10 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
|
|
|
@Nullable
|
|
private Map<EquipmentSlot, ItemStack> collectEquipmentChanges() {
|
|
+ // Leaf start - Lithium - equipment tracking
|
|
+ final boolean isArmorStandUpdateNoTick = this instanceof net.minecraft.world.entity.decoration.ArmorStand stand && !stand.canTick && stand.noTickEquipmentDirty;
|
|
+ if (!isArmorStandUpdateNoTick && !this.equipment.lithium$hasUnsentEquipmentChanges()) return null;
|
|
+ // Leaf end - Lithium - equipment tracking
|
|
Map<EquipmentSlot, ItemStack> map = null;
|
|
// Paper start - EntityEquipmentChangedEvent
|
|
record EquipmentChangeImpl(org.bukkit.inventory.ItemStack oldItem, org.bukkit.inventory.ItemStack newItem) implements io.papermc.paper.event.entity.EntityEquipmentChangedEvent.EquipmentChange {
|
|
diff --git a/net/minecraft/world/entity/decoration/ArmorStand.java b/net/minecraft/world/entity/decoration/ArmorStand.java
|
|
index 98a1795be167d4ecde25a89ba031827ccbd14483..745d548c1574233f34206260a051fd77bdacd1f3 100644
|
|
--- a/net/minecraft/world/entity/decoration/ArmorStand.java
|
|
+++ b/net/minecraft/world/entity/decoration/ArmorStand.java
|
|
@@ -528,8 +528,9 @@ public class ArmorStand extends LivingEntity {
|
|
maxUpStep = level().purpurConfig.armorstandStepHeight; // Purpur - Add option to set armorstand step height
|
|
if (!this.canTick) {
|
|
if (this.noTickEquipmentDirty) {
|
|
- this.noTickEquipmentDirty = false;
|
|
+ //this.noTickEquipmentDirty = false; // Leaf - Lithium - equipment tracking - move down
|
|
this.detectEquipmentUpdates();
|
|
+ this.noTickEquipmentDirty = false; // Leaf - Lithium - equipment tracking
|
|
}
|
|
|
|
return;
|
|
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
|
index f5ca3d6b29b11475ac56cd206464577b2d85b7dc..b4a196533e81c9e003325f885d1ebaebe540ebe5 100644
|
|
--- a/net/minecraft/world/item/ItemStack.java
|
|
+++ b/net/minecraft/world/item/ItemStack.java
|
|
@@ -94,7 +94,7 @@ import org.apache.commons.lang3.function.TriConsumer;
|
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
|
import org.slf4j.Logger;
|
|
|
|
-public final class ItemStack implements DataComponentHolder {
|
|
+public final class ItemStack implements DataComponentHolder, net.caffeinemc.mods.lithium.common.util.change_tracking.ChangePublisher<ItemStack>, net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber<PatchedDataComponentMap> { // Leaf - Lithium - equipment tracking
|
|
private static final List<Component> OP_NBT_WARNING = List.of(
|
|
Component.translatable("item.op_warning.line1").withStyle(ChatFormatting.RED, ChatFormatting.BOLD),
|
|
Component.translatable("item.op_warning.line2").withStyle(ChatFormatting.RED),
|
|
@@ -165,6 +165,11 @@ public final class ItemStack implements DataComponentHolder {
|
|
PatchedDataComponentMap components;
|
|
@Nullable
|
|
private Entity entityRepresentation;
|
|
+ // Leaf start - Lithium - equipment tracking
|
|
+ @Nullable
|
|
+ private net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber<ItemStack> subscriber;
|
|
+ private int subscriberData;
|
|
+ // Leaf end - Lithium - equipment tracking
|
|
|
|
public static DataResult<ItemStack> validateStrict(ItemStack stack) {
|
|
DataResult<Unit> dataResult = validateComponents(stack.getComponents());
|
|
@@ -1330,6 +1335,21 @@ public final class ItemStack implements DataComponentHolder {
|
|
}
|
|
|
|
public void setCount(int count) {
|
|
+ // Leaf start - Lithium - equipment tracking
|
|
+ if (count != this.count) {
|
|
+ if (this.subscriber instanceof net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.CountChangeSubscriber<ItemStack> countChangeSubscriber) {
|
|
+ countChangeSubscriber.lithium$notifyCount(this, this.subscriberData, count);
|
|
+ }
|
|
+ if (count == 0) {
|
|
+ this.components.lithium$unsubscribe(this);
|
|
+ if (this.subscriber != null) {
|
|
+ this.subscriber.lithium$forceUnsubscribe(this, this.subscriberData);
|
|
+ this.subscriber = null;
|
|
+ this.subscriberData = 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Leaf end - Lithium - equipment tracking
|
|
this.count = count;
|
|
}
|
|
|
|
@@ -1385,4 +1405,87 @@ public final class ItemStack implements DataComponentHolder {
|
|
public boolean canDestroyBlock(BlockState state, Level level, BlockPos pos, Player player) {
|
|
return this.getItem().canDestroyBlock(this, state, level, pos, player);
|
|
}
|
|
+
|
|
+ // Leaf start - Lithium - equipment tracking
|
|
+ @Override
|
|
+ public void lithium$subscribe(net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber<ItemStack> subscriber, int subscriberData) {
|
|
+ if (this.isEmpty()) {
|
|
+ throw new IllegalStateException("Cannot subscribe to an empty ItemStack!");
|
|
+ }
|
|
+
|
|
+ if (this.subscriber == null) {
|
|
+ this.startTrackingChanges();
|
|
+ }
|
|
+ this.subscriber = net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.combine(this.subscriber, this.subscriberData, subscriber, subscriberData);
|
|
+ if (this.subscriber instanceof net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.Multi<?>) {
|
|
+ this.subscriberData = 0;
|
|
+ } else {
|
|
+ this.subscriberData = subscriberData;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int lithium$unsubscribe(net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber<ItemStack> subscriber) {
|
|
+ if (this.isEmpty()) {
|
|
+ throw new IllegalStateException("Cannot unsubscribe from an empty ItemStack!");
|
|
+ }
|
|
+
|
|
+ int retval = net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.dataOf(this.subscriber, subscriber, this.subscriberData);
|
|
+ this.subscriberData = net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.dataWithout(this.subscriber, subscriber, this.subscriberData);
|
|
+ this.subscriber = net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.without(this.subscriber, subscriber);
|
|
+
|
|
+ if (this.subscriber == null) {
|
|
+ this.components.lithium$unsubscribe(this);
|
|
+ }
|
|
+ return retval;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void lithium$unsubscribeWithData(net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber<ItemStack> subscriber, int subscriberData) {
|
|
+ if (this.isEmpty()) {
|
|
+ throw new IllegalStateException("Cannot unsubscribe from an empty ItemStack!");
|
|
+ }
|
|
+
|
|
+ this.subscriberData = net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.dataWithout(this.subscriber, subscriber, this.subscriberData, subscriberData, true);
|
|
+ this.subscriber = net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.without(this.subscriber, subscriber, subscriberData, true);
|
|
+
|
|
+ if (this.subscriber == null) {
|
|
+ this.components.lithium$unsubscribe(this);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean lithium$isSubscribedWithData(net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber<ItemStack> subscriber, int subscriberData) {
|
|
+ if (this.isEmpty()) {
|
|
+ throw new IllegalStateException("Cannot be subscribed to an empty ItemStack!");
|
|
+ }
|
|
+
|
|
+ return net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.containsSubscriber(this.subscriber, this.subscriberData, subscriber, subscriberData);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void lithium$forceUnsubscribe(PatchedDataComponentMap publisher, int subscriberData) {
|
|
+ if (publisher != this.components) {
|
|
+ throw new IllegalStateException("Invalid publisher, expected " + this.components + " but got " + publisher);
|
|
+ }
|
|
+ this.subscriber.lithium$forceUnsubscribe(this, this.subscriberData);
|
|
+ this.subscriber = null;
|
|
+ this.subscriberData = 0;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void lithium$notify(PatchedDataComponentMap publisher, int subscriberData) {
|
|
+ if (publisher != this.components) {
|
|
+ throw new IllegalStateException("Invalid publisher, expected " + this.components + " but got " + publisher);
|
|
+ }
|
|
+
|
|
+ if (this.subscriber != null) {
|
|
+ this.subscriber.lithium$notify(this, this.subscriberData);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void startTrackingChanges() {
|
|
+ this.components.lithium$subscribe(this, 0);
|
|
+ }
|
|
+ // Leaf end - Lithium - equipment tracking
|
|
}
|