From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Thu, 14 Aug 2025 14:12:38 +0900 Subject: [PATCH] optimize attribute diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java index 61a9d3012eb7a8bfdd3867606cd1b144f6170de2..85c811666b5cc4a01ccb97cef0cf350570bc12c6 100644 --- a/net/minecraft/server/level/ServerEntity.java +++ b/net/minecraft/server/level/ServerEntity.java @@ -463,7 +463,7 @@ public class ServerEntity { this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync)); } - attributesToSync.clear(); + // attributesToSync.clear(); // Leaf - optimize attribute } } diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java index 500f62505d56c51ea6a21280152852db02c086b8..36859e17275a38d7acc82fcad8762bfc642811a1 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java @@ -370,7 +370,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin .add(Attributes.CAMERA_DISTANCE) .add(Attributes.WAYPOINT_TRANSMIT_RANGE); } - public boolean shouldSendAttribute(Attribute attribute) { return true; } // Purpur - Ridables + public boolean shouldSendAttribute(Attribute attribute) { return true; } // Purpur - Ridables // Leaf - optimize attribute - diff on change @Override protected void checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos) { @@ -1345,13 +1345,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin } private void refreshDirtyAttributes() { - Set attributesToUpdate = this.getAttributes().getAttributesToUpdate(); + // Leaf start - optimize attribute + int[] attributesToUpdate = this.getAttributes().getAttributesToUpdateIds(); - for (AttributeInstance attributeInstance : attributesToUpdate) { - this.onAttributeUpdated(attributeInstance.getAttribute()); + for (int attribute : attributesToUpdate) { + this.onAttributeUpdated(org.dreeam.leaf.util.RegistryTypeManager.ATTRIBUTE[attribute]); } - - attributesToUpdate.clear(); + // Leaf end - optimize attribute } protected void onAttributeUpdated(Holder attribute) { diff --git a/net/minecraft/world/entity/ai/attributes/Attribute.java b/net/minecraft/world/entity/ai/attributes/Attribute.java index 18563961e9dba1a11265c6ea708881d4e46846ff..ad3fee2adde07055e1ce69a069fd4201020a47ea 100644 --- a/net/minecraft/world/entity/ai/attributes/Attribute.java +++ b/net/minecraft/world/entity/ai/attributes/Attribute.java @@ -16,10 +16,15 @@ public class Attribute { private boolean syncable; private final String descriptionId; public Attribute.Sentiment sentiment = Attribute.Sentiment.POSITIVE; + // Leaf start - optimize attribute + public final int id; + private static int size = 0; + // Leaf end - optimize attribute protected Attribute(String descriptionId, double defaultValue) { this.defaultValue = defaultValue; this.descriptionId = descriptionId; + this.id = size++; // Leaf - optimize attribute } public double getDefaultValue() { diff --git a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java index 42ad600c6a5cb20e1d820f169f6a1a17ef3a5195..df5f51f6a2921a7c1f1b2d17938a704c61102ba3 100644 --- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java +++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java @@ -52,16 +52,19 @@ public class AttributeInstance { @VisibleForTesting Map getModifiers(AttributeModifier.Operation operation) { - return this.modifiersByOperation.computeIfAbsent(operation, operation1 -> new Object2ObjectOpenHashMap<>()); + return this.modifiersByOperation.computeIfAbsent(operation, operation1 -> new Object2ObjectArrayMap<>()); // Leaf - optimize attribute } + // Leaf start - optimize attribute + private static final AttributeModifier[] EMPTY_ATTRIBUTE_MODIFIER_ARRAY = {}; public Set getModifiers() { - return ImmutableSet.copyOf(this.modifierById.values()); + return this.modifierById.isEmpty() ? Set.of() : it.unimi.dsi.fastutil.objects.ObjectArraySet.ofUnchecked(this.modifierById.values().toArray(EMPTY_ATTRIBUTE_MODIFIER_ARRAY)); } public Set getPermanentModifiers() { - return ImmutableSet.copyOf(this.permanentModifiers.values()); + return this.permanentModifiers.isEmpty() ? Set.of() : it.unimi.dsi.fastutil.objects.ObjectArraySet.ofUnchecked(this.permanentModifiers.values().toArray(EMPTY_ATTRIBUTE_MODIFIER_ARRAY)); } + // Leaf end - optimize attribute @Nullable public AttributeModifier getModifier(ResourceLocation id) { @@ -139,12 +142,15 @@ public class AttributeInstance { } public double getValue() { - if (this.dirty) { - this.cachedValue = this.calculateValue(); - this.dirty = false; + // Leaf start - optimize attribute + if (!this.dirty) { + return this.cachedValue; } - - return this.cachedValue; + double value = this.calculateValue(); + this.cachedValue = value; + this.dirty = false; + return value; + // Leaf end - optimize attribute } private double calculateValue() { diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java index a65ba1712d55d23abdbb192f13ffb972be308e84..4395afb167217c92213d646dc2cd42d786798843 100644 --- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java +++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java @@ -13,12 +13,12 @@ import javax.annotation.Nullable; import net.minecraft.core.Holder; import net.minecraft.resources.ResourceLocation; -public class AttributeMap { - // Gale start - Lithium - replace AI attributes with optimized collections - public final Map, AttributeInstance> attributes = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0); - private final Set attributesToSync = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0); - private final Set attributesToUpdate = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0); - // Gale end - Lithium - replace AI attributes with optimized collections +public class AttributeMap implements java.util.function.Consumer { // Leaf - optimize attribute + // Leaf start - optimize attribute + public final Map, AttributeInstance> attributes = new org.dreeam.leaf.util.map.AttributeInstanceArrayMap(); + private final Set attributesToSync = new org.dreeam.leaf.util.map.AttributeInstanceSet((org.dreeam.leaf.util.map.AttributeInstanceArrayMap) attributes); + private final Set attributesToUpdate = new org.dreeam.leaf.util.map.AttributeInstanceSet((org.dreeam.leaf.util.map.AttributeInstanceArrayMap) attributes); + // Leaf end - optimize attribute private final AttributeSupplier supplier; private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables @@ -27,34 +27,109 @@ public class AttributeMap { this(supplier, null); } public AttributeMap(AttributeSupplier defaultAttributes, net.minecraft.world.entity.LivingEntity entity) { - this.entity = entity; + this.entity = entity instanceof net.minecraft.world.entity.ambient.Bat ? entity : null; // Leaf - optimize attribute - only check bat // Purpur end - Ridables this.supplier = defaultAttributes; } private void onAttributeModified(AttributeInstance instance) { - this.attributesToUpdate.add(instance); - if (instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur - Ridables - this.attributesToSync.add(instance); + // Leaf start - optimize attribute + Attribute attribute = instance.getAttribute().value(); + ((org.dreeam.leaf.util.map.AttributeInstanceSet)this.attributesToUpdate).addAttribute(attribute); + if (attribute.isClientSyncable() && (entity == null || entity.shouldSendAttribute(attribute))) { // Purpur - Ridables + ((org.dreeam.leaf.util.map.AttributeInstanceSet)this.attributesToSync).addAttribute(attribute); } + // Leaf end - optimize attribute } + // Leaf start - optimize attribute + @Override + public void accept(AttributeInstance instance) { + this.onAttributeModified(instance); + } + + private static final AttributeInstance[] EMPTY_ATTRIBUTE_INSTANCE = new AttributeInstance[0]; + @Deprecated public Set getAttributesToSync() { - return this.attributesToSync; + if (attributesToSync.isEmpty()) { + return Set.of(); + } + it.unimi.dsi.fastutil.objects.ReferenceArraySet clone = it.unimi.dsi.fastutil.objects.ReferenceArraySet.ofUnchecked(attributesToSync.toArray(EMPTY_ATTRIBUTE_INSTANCE)); + this.attributesToSync.clear(); + return clone; } + @Deprecated public Set getAttributesToUpdate() { - return this.attributesToUpdate; + if (attributesToUpdate.isEmpty()) { + return Set.of(); + } + it.unimi.dsi.fastutil.objects.ReferenceArraySet clone = it.unimi.dsi.fastutil.objects.ReferenceArraySet.ofUnchecked(attributesToUpdate.toArray(EMPTY_ATTRIBUTE_INSTANCE)); + this.attributesToUpdate.clear(); + return clone; + } + + public boolean attributeDirty() { + return !attributesToSync.isEmpty(); + } + + public int[] getAttributesToUpdateIds() { + int[] clone = ((org.dreeam.leaf.util.map.AttributeInstanceSet)attributesToUpdate).inner.toIntArray(); + this.attributesToUpdate.clear(); + return clone; + } + + public int[] getAttributesToSyncIds() { + int[] clone = ((org.dreeam.leaf.util.map.AttributeInstanceSet)attributesToSync).inner.toIntArray(); + this.attributesToSync.clear(); + return clone; } public Collection getSyncableAttributes() { - return this.attributes.values().stream().filter(instance -> instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))).collect(Collectors.toList()); // Purpur - Ridables + List list = new ArrayList<>(this.attributes.size()); + for (AttributeInstance instance : this.attributes.values()) { + if (instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur - Ridables + list.add(instance); + } + } + return list; + } + + public List getSyncableAttributesPacket() { + List list = new ArrayList<>(attributes.size()); + if (attributes instanceof org.dreeam.leaf.util.map.AttributeInstanceArrayMap map) { + for (AttributeInstance instance : map.elements()) { + if (instance != null && instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur - Ridables + list.add(new net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket.AttributeSnapshot( + instance.getAttribute(), instance.getBaseValue(), instance.getModifiers() + )); + } + } + } else { + for (AttributeInstance instance : attributes.values()) { + if (instance != null && instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur - Ridables + list.add(new net.minecraft.network.protocol.game.ClientboundUpdateAttributesPacket.AttributeSnapshot( + instance.getAttribute(), instance.getBaseValue(), instance.getModifiers() + )); + } + } + } + return list; } @Nullable public AttributeInstance getInstance(Holder attribute) { - return this.attributes.computeIfAbsent(attribute, holder -> this.supplier.createInstance(this::onAttributeModified, (Holder)holder)); + AttributeInstance v; + if ((v = this.attributes.get(attribute)) == null) { + AttributeInstance newValue; + if ((newValue = this.supplier.createInstance(this, attribute)) != null) { + attributes.put(attribute, newValue); + return newValue; + } + } + return v; } + // Leaf end - optimize attribute public boolean hasAttribute(Holder attribute) { return this.attributes.get(attribute) != null || this.supplier.hasAttribute(attribute); diff --git a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java index 24710041ccbc70e5506d8d89ae34f0141977f209..a428848f7ada657e171c8ed78c52935cef53aadf 100644 --- a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java +++ b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java @@ -11,7 +11,7 @@ public class AttributeSupplier { private final Map, AttributeInstance> instances; AttributeSupplier(Map, AttributeInstance> instances) { - this.instances = instances; + this.instances = new org.dreeam.leaf.util.map.AttributeInstanceArrayMap(instances); // Leaf - optimize attribute } public AttributeInstance getAttributeInstance(Holder attribute) {