9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-19 14:59:25 +00:00
Files
DivineMC/divinemc-server/minecraft-patches/features/0071-lithium-equipment_tracking.patch
wiyba 6e0570e215 Updated Upstream (Purpur)
Upstream has released updates that appear to apply and compile correctly

Purpur Changes:
2025-10-31 15:33:03 +03:00

251 lines
12 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Wed, 1 Oct 2025 01:49:00 +0300
Subject: [PATCH] lithium: equipment_tracking
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/world/entity/EntityEquipment.java b/net/minecraft/world/entity/EntityEquipment.java
index 1e00a7bd89d885cabb4b9ca3c86fbd8cd93cebf5..4fb31f578c2a4a5dc137c38de8f641597ce80465 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.util.change_tracking.ChangeSubscriber.CountChangeSubscriber<net.minecraft.world.item.ItemStack> { // DivineMC - 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;
+ // DivineMC start - lithium: equipment_tracking
+ boolean shouldTickEnchantments = false;
+ ItemStack recheckEnchantmentForStack = null;
+ boolean hasUnsentEquipmentChanges = true;
+ // DivineMC end - lithium: equipment_tracking
private EntityEquipment(EnumMap<EquipmentSlot, ItemStack> items) {
this.items = items;
@@ -28,7 +33,13 @@ public class EntityEquipment {
}
public ItemStack set(EquipmentSlot slot, ItemStack stack) {
- return Objects.requireNonNullElse(this.items.put(slot, stack), ItemStack.EMPTY);
+ // DivineMC start - lithium: equipment_tracking
+ ItemStack oldStack = Objects.requireNonNullElse(this.items.put(slot, stack), ItemStack.EMPTY);
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) {
+ this.onEquipmentReplaced(oldStack, stack);
+ }
+ return oldStack;
+ // DivineMC end - lithium: equipment_tracking
}
public ItemStack get(EquipmentSlot slot) {
@@ -55,8 +66,23 @@ public class EntityEquipment {
}
public void setAll(EntityEquipment equipment) {
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) this.onClear(); // DivineMC - lithium: equipment_tracking
this.items.clear();
this.items.putAll(equipment.items);
+ // DivineMC start - lithium: equipment_tracking
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) {
+ for (net.minecraft.world.item.ItemStack newStack : this.items.values()) {
+ if (!newStack.isEmpty()) {
+ if (!this.shouldTickEnchantments) {
+ this.shouldTickEnchantments = stackHasTickableEnchantment(newStack);
+ }
+ if (!newStack.isEmpty()) {
+ newStack.lithium$subscribe(this, 0);
+ }
+ }
+ }
+ }
+ // DivineMC end - lithium: equipment_tracking
}
public void dropAll(LivingEntity entity) {
@@ -69,6 +95,7 @@ public class EntityEquipment {
public void clear() {
this.items.replaceAll((equipmentSlot, itemStack) -> ItemStack.EMPTY);
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) this.onClear(); // DivineMC - lithium: equipment_tracking
}
// Paper start - EntityDeathEvent
@@ -77,4 +104,98 @@ public class EntityEquipment {
return this.items.containsKey(slot);
}
// Paper end - EntityDeathEvent
+
+ // DivineMC start - lithium: equipment_tracking
+ public boolean lithium$shouldTickEnchantments() {
+ this.processScheduledEnchantmentCheck(null);
+ return this.shouldTickEnchantments;
+ }
+
+ public boolean lithium$hasUnsentEquipmentChanges() {
+ return this.hasUnsentEquipmentChanges;
+ }
+
+ 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();
+ }
+ // DivineMC end - lithium: equipment_tracking
}
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 7ec1c2f39981b60343f152a5432b3677574ee46c..e3e64a0bf7b8b9e04114a2b0b363932517deea0f 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -440,9 +440,17 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
this.getSleepingPos().ifPresent(this::setPosToBed);
}
- if (this.level() instanceof ServerLevel serverLevel) {
- EnchantmentHelper.tickEffects(serverLevel, this);
+ // DivineMC start - lithium: equipment_tracking
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) {
+ if ((this instanceof Player || this.equipment.lithium$shouldTickEnchantments()) && this.level() instanceof ServerLevel serverLevel) {
+ EnchantmentHelper.tickEffects(serverLevel, this);
+ }
+ } else {
+ if (this.level() instanceof ServerLevel serverLevel) {
+ EnchantmentHelper.tickEffects(serverLevel, this);
+ }
}
+ // DivineMC end - lithium: equipment_tracking
super.baseTick();
if (this.isAlive() && this.level() instanceof ServerLevel serverLevel1) {
@@ -3454,6 +3462,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
public void detectEquipmentUpdates() {
Map<EquipmentSlot, ItemStack> map = this.collectEquipmentChanges();
if (map != null) {
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking && !(this instanceof net.minecraft.world.entity.player.Player)) this.equipment.lithium$onEquipmentChangesSent(); // DivineMC - lithium: equipment_tracking
this.handleHandSwap(map);
if (!map.isEmpty()) {
this.handleEquipmentChanges(map);
@@ -3463,6 +3472,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@Nullable
private Map<EquipmentSlot, ItemStack> collectEquipmentChanges() {
+ // DivineMC start - lithium: equipment_tracking
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) {
+ final boolean isArmorStandUpdateNoTick = this instanceof net.minecraft.world.entity.decoration.ArmorStand stand && !stand.canTick && stand.noTickEquipmentDirty;
+ if (!isArmorStandUpdateNoTick && !this.equipment.lithium$hasUnsentEquipmentChanges()) {
+ return null;
+ }
+ }
+ // DivineMC 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 9a298e111b9142dd878ee03b442d1110a9e0897e..ff3a4d740631d9f353cf1812f124b68aac144f64 100644
--- a/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/net/minecraft/world/entity/decoration/ArmorStand.java
@@ -529,8 +529,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;
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) this.noTickEquipmentDirty = false; // DivineMC - lithium: equipment_tracking
this.detectEquipmentUpdates();
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) this.noTickEquipmentDirty = false; // DivineMC - lithium: equipment_tracking
}
return;