mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-22 08:19:19 +00:00
feat: lithium: equipment_tracking
This commit is contained in:
@@ -8,6 +8,7 @@ private-f net.minecraft.world.level.levelgen.RandomState router
|
||||
private-f net.minecraft.world.level.levelgen.RandomState sampler
|
||||
public net.minecraft.core.NonNullList list
|
||||
public net.minecraft.util.Mth SIN
|
||||
public net.minecraft.world.entity.Entity levelCallback
|
||||
public net.minecraft.world.entity.ai.Brain sensors
|
||||
public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities lineOfSightTest
|
||||
public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities nearbyEntities
|
||||
@@ -15,6 +16,7 @@ public net.minecraft.world.entity.ai.sensing.Sensor scanRate
|
||||
public net.minecraft.world.entity.ai.sensing.Sensor timeToTick
|
||||
public net.minecraft.world.entity.animal.armadillo.Armadillo scuteTime
|
||||
public net.minecraft.world.entity.animal.frog.Tadpole getTicksLeftUntilAdult()I
|
||||
public net.minecraft.world.entity.decoration.ArmorStand noTickEquipmentDirty
|
||||
public net.minecraft.world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapper
|
||||
public net.minecraft.world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapper rebind(Lnet/minecraft/world/level/block/entity/TickingBlockEntity;)V
|
||||
public net.minecraft.world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapper ticker
|
||||
|
||||
@@ -96,18 +96,9 @@ index b382665cc125b8b5c0938e5e55984e4bf91d37ff..c112b58996494d97fcd226fc490fe271
|
||||
|
||||
int getContainerSize();
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 2c7c5dab268625e1328f57ac3ec2a735a82fea42..5d0d94475a6045f256fac0d997c0cb40c2d4a07e 100644
|
||||
index d82ed6dcd49b4f0bd040d2bd3a6f0f54cd87758f..bae2cf89e9bc71a360fe471f7d3e703705488f3a 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -308,7 +308,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
private static final EntityDataAccessor<Boolean> DATA_NO_GRAVITY = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.BOOLEAN);
|
||||
protected static final EntityDataAccessor<Pose> DATA_POSE = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.POSE);
|
||||
public static final EntityDataAccessor<Integer> DATA_TICKS_FROZEN = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.INT);
|
||||
- private EntityInLevelCallback levelCallback = EntityInLevelCallback.NULL;
|
||||
+ public EntityInLevelCallback levelCallback = EntityInLevelCallback.NULL; // DivineMC - lithium: sleeping_block_entity - private -> public
|
||||
private final VecDeltaCodec packetPositionCodec = new VecDeltaCodec();
|
||||
public boolean hasImpulse;
|
||||
@Nullable
|
||||
@@ -5075,6 +5075,18 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.setBoundingBox(this.makeBoundingBox());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
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 90814ad07a2686c5a274860395f5aca29cc3bf13..21119ff49d6d59aff48ce9fbf76a51fa296cd1c1 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;
|
||||
@@ -29,7 +34,13 @@ public class EntityEquipment {
|
||||
|
||||
public ItemStack set(EquipmentSlot slot, ItemStack stack) {
|
||||
stack.getItem().verifyComponentsAfterLoad(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) {
|
||||
@@ -56,8 +67,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) {
|
||||
@@ -70,6 +96,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
|
||||
@@ -78,4 +105,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 e903e60c8914899d9be14cce9fdef9cc33ee71d5..1e27701cf4de424ee9685bd061afc9706996e8da 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -433,9 +433,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.fireImmune() || this.level().isClientSide) {
|
||||
@@ -3413,6 +3421,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);
|
||||
@@ -3422,6 +3431,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 83fdd22eeb141079e05018ebf5cef70e7eb78726..81f6d57e6bd225998f4c44a78b4aab2166fde1f0 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;
|
||||
+ 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;
|
||||
@@ -379,6 +379,7 @@ public class DivineConfig {
|
||||
public static boolean reduceChuckLoadAndLookup = true;
|
||||
public static boolean createSnapshotOnRetrievingBlockState = true;
|
||||
public static boolean sleepingBlockEntity = false;
|
||||
public static boolean equipmentTracking = false;
|
||||
public static boolean hopperThrottleWhenFull = false;
|
||||
public static int hopperThrottleSkipTicks = 0;
|
||||
|
||||
@@ -485,6 +486,8 @@ public class DivineConfig {
|
||||
"If false, plugins get direct BlockState access for better performance but risk data corruption from poor plugin design.");
|
||||
sleepingBlockEntity = getBoolean(ConfigCategory.PERFORMANCE.key("optimizations.sleeping-block-entity"), sleepingBlockEntity,
|
||||
"When enabled, block entities will enter a sleep state when they are inactive.");
|
||||
equipmentTracking = getBoolean(ConfigCategory.PERFORMANCE.key("optimizations.equipment-tracking"), equipmentTracking,
|
||||
"When enabled, skips repeated checks whether the equipment of an entity changed.");
|
||||
|
||||
hopperThrottleWhenFull = getBoolean(ConfigCategory.PERFORMANCE.key("optimizations.hopper-throttle-when-full.enabled"), hopperThrottleWhenFull,
|
||||
"When enabled, hoppers will throttle if target container is full.");
|
||||
|
||||
Reference in New Issue
Block a user