mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-19 15:09:25 +00:00
Update changes from ver/1.21.4 branch
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Wed, 4 Jun 2025 20:54:32 +0900
|
||||
Subject: [PATCH] preload mob spawning position
|
||||
|
||||
Removed since Leaf 1.21.4, No need
|
||||
|
||||
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 458b17dca84c87591b030679c5aac6259c0f8308..c69922ac2b831d8af35c9e98a34825e6b8a268da 100644
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -257,9 +257,57 @@ public final class NaturalSpawner {
|
||||
// Paper end - Optional per player mob spawns
|
||||
// Leaf start - optimize mob spawning
|
||||
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
- mutableRandomPosWithin(pos, level, chunk);
|
||||
- if (pos.getY() < level.getMinY() + 1) {
|
||||
- return 0;
|
||||
+ // Leaf start - preload mob spawning position
|
||||
+ if (org.dreeam.leaf.config.modules.opt.PreloadNaturalMobSpawning.enabled) {
|
||||
+ if (chunk.cacheSpawnPosIndex == 16 || chunk.cacheSpawnPosIndex == -1) {
|
||||
+ if (chunk.cacheSpawnPos == null) {
|
||||
+ chunk.cacheSpawnPos = new long[16];
|
||||
+ }
|
||||
+ // cache friendly
|
||||
+ for (int i = 0; i < 16; i++) {
|
||||
+ mutableRandomPosWithin(pos, level, chunk);
|
||||
+ if (pos.getY() >= level.getMinY() + 1
|
||||
+ && level.getWorldBorder().isWithinBounds(pos)
|
||||
+ && !level.isOutsideBuildHeight(pos)) {
|
||||
+ LevelChunk chunk1 = chunk.getPos().longKey == ChunkPos.asLong(pos)
|
||||
+ ? chunk
|
||||
+ : level.chunkSource.getChunkAtIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4);
|
||||
+ if (chunk1 != null) {
|
||||
+ BlockState bs = chunk1.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ if (bs != null && !bs.isRedstoneConductor(level, pos)) {
|
||||
+ chunk.cacheSpawnPos[i] = BlockPos.asLong(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ chunk.cacheSpawnPos[i] = -1;
|
||||
+ }
|
||||
+ chunk.cacheSpawnPosIndex = 0;
|
||||
+ }
|
||||
+ long cachePos = chunk.cacheSpawnPos[chunk.cacheSpawnPosIndex];
|
||||
+ chunk.cacheSpawnPosIndex++;
|
||||
+ if (cachePos == -1) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ pos.set(cachePos);
|
||||
+ } else {
|
||||
+ mutableRandomPosWithin(pos, level, chunk);
|
||||
+ if (pos.getY() < level.getMinY() + 1
|
||||
+ || !level.getWorldBorder().isWithinBounds(pos)
|
||||
+ || level.isOutsideBuildHeight(pos)) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ LevelChunk chunk1 = chunk.getPos().longKey == ChunkPos.asLong(pos)
|
||||
+ ? chunk
|
||||
+ : level.chunkSource.getChunkAtIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4);
|
||||
+ if (chunk1 == null) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ BlockState bs = chunk1.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ if (bs == null || bs.isRedstoneConductor(level, pos)) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ // Leaf end - preload mob spawning position
|
||||
}
|
||||
return spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false); // Paper - Optional per player mob spawns // Paper - throttle failed spawn attempts
|
||||
// Leaf end - optimize mob spawning
|
||||
@@ -284,7 +332,12 @@ public final class NaturalSpawner {
|
||||
MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer<Entity> trackEntity
|
||||
// Paper start - throttle failed spawn attempts
|
||||
) {
|
||||
- spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false);
|
||||
+ // Leaf start - preload mob spawning position
|
||||
+ BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos);
|
||||
+ if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) {
|
||||
+ spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false);
|
||||
+ }
|
||||
+ // Leaf end - preload mob spawning position
|
||||
}
|
||||
public static int spawnCategoryForPosition(
|
||||
MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer<Entity> trackEntity, final boolean nothing
|
||||
@@ -297,8 +350,8 @@ public final class NaturalSpawner {
|
||||
int posX = pos.getX(); // Leaf - optimize mob spawning
|
||||
int posZ = pos.getZ(); // Leaf - optimize mob spawning
|
||||
int i = 0; // Paper - throttle failed spawn attempts
|
||||
- BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
|
||||
- if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn
|
||||
+ //BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn // Leaf - preload mob spawning position
|
||||
+ if (true /*blockState != null && !blockState.isRedstoneConductor(chunk, pos)*/) { // Paper - don't load chunks for mob spawn // Leaf - preload mob spawning position
|
||||
BlockPos.MutableBlockPos mutableBlockPos = pos instanceof BlockPos.MutableBlockPos pos2 ? pos2 : new BlockPos.MutableBlockPos(); // Leaf - optimize mob spawning
|
||||
//int i = 0; // Paper - throttle failed spawn attempts - move up
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index a90bf0d80ae4dac9b19b8e467b402917cc19a271..804f2118167b1607c50ca8378119254e8760427a 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -106,6 +106,8 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
// Paper start - rewrite chunk system
|
||||
private boolean postProcessingDone;
|
||||
private net.minecraft.server.level.ServerChunkCache.ChunkAndHolder chunkAndHolder;
|
||||
+ public long[] cacheSpawnPos = null; // Leaf - preload mob spawning position
|
||||
+ public int cacheSpawnPosIndex = -1; // Leaf - preload mob spawning position
|
||||
|
||||
@Override
|
||||
public final boolean moonrise$isPostProcessingDone() {
|
||||
@@ -0,0 +1,426 @@
|
||||
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
|
||||
|
||||
TODO: needs to fix issues related to Piglins lose the crossbow animation
|
||||
original report is in discord.
|
||||
|
||||
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-fabric)
|
||||
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..369f0176a636def905fb2a2df1a0e2cadd1eb3b2 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 newStack = Objects.requireNonNullElse(this.items.put(slot, stack), ItemStack.EMPTY);
|
||||
+ this.onEquipmentReplaced(this.get(slot), newStack);
|
||||
+ return newStack;
|
||||
+ // 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 b3e9ad0669bb4b91d5d991f106b225e914a4e68f..a927e8a7d9149f5b7abaae50ba8d4fdc6ec87b55 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -417,7 +417,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -3394,6 +3394,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
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);
|
||||
@@ -3403,6 +3404,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
@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 0417175c7beabbca53cd080d158001eabe3941f0..cb2a8f9cff99a7a906bc7be09d301728742bc11e 100644
|
||||
--- a/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
+++ b/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
@@ -559,8 +559,8 @@ public class ArmorStand extends LivingEntity {
|
||||
}
|
||||
|
||||
if (this.noTickEquipmentDirty) {
|
||||
- this.noTickEquipmentDirty = false;
|
||||
this.detectEquipmentUpdates();
|
||||
+ this.noTickEquipmentDirty = false; // Leaf - Lithium - equipment tracking - Remove dirty mark after handling equipment update for armor stand
|
||||
}
|
||||
|
||||
return;
|
||||
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
||||
index 07f1b27116baf2a06e6cd4eeaa8639e166fb362d..d1c8b4a2a32d49d90f2f2aa460915d319a781535 100644
|
||||
--- a/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/net/minecraft/world/item/ItemStack.java
|
||||
@@ -97,7 +97,7 @@ import net.minecraft.world.level.block.state.pattern.BlockInWorld;
|
||||
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),
|
||||
@@ -168,6 +168,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());
|
||||
@@ -1402,6 +1407,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;
|
||||
}
|
||||
|
||||
@@ -1457,4 +1477,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
|
||||
}
|
||||
Reference in New Issue
Block a user