9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2026-01-03 22:26:19 +00:00
Files
Leaf/leaf-server/minecraft-patches/features/0249-Optimize-isEyeInFluid.patch
Dreeam 9a4efaa230 Drop patch that causes performance regression
Originally vanilla logic is to use stream, and Mojang switched it to Guava's Collections2
since 1.21.4. It is much faster than using stream or manually adding to a new ArrayList.
Manually adding to a new ArrayList requires allocating a new object array. However, the Collections2
lazy handles filter condition on iteration, so much better.
2025-08-04 19:25:56 +08:00

317 lines
16 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wling-art <wlingzhenyu@163.com>
Date: Sat, 17 May 2025 08:25:33 +0800
Subject: [PATCH] Optimize isEyeInFluid
diff --git a/net/minecraft/core/Holder.java b/net/minecraft/core/Holder.java
index 6c7edbbf3935c40ccb78bee680ea75431718b9bd..fd2f79d976c9587b00380f8b8f784b32ca294673 100644
--- a/net/minecraft/core/Holder.java
+++ b/net/minecraft/core/Holder.java
@@ -29,6 +29,8 @@ public interface Holder<T> {
Stream<TagKey<T>> tags();
+ TagKey<T>[] tagArray(); // Leaf - Optimize isEyeInFluid
+
Either<ResourceKey<T>, T> unwrap();
Optional<ResourceKey<T>> unwrapKey();
@@ -105,6 +107,13 @@ public interface Holder<T> {
public Stream<TagKey<T>> tags() {
return Stream.of();
}
+
+ // Leaf start - Optimize isEyeInFluid
+ @Override
+ public TagKey<T>[] tagArray() {
+ return me.titaniumtown.ArrayConstants.emptyTagKeyArray;
+ }
+ // Leaf end - Optimize isEyeInFluid
}
public static enum Kind {
@@ -116,6 +125,7 @@ public interface Holder<T> {
private final HolderOwner<T> owner;
@Nullable
private Set<TagKey<T>> tags;
+ @Nullable private TagKey<T>[] tagArray; // Leaf - Optimize isEyeInFluid
private final Holder.Reference.Type type;
@Nullable
private ResourceKey<T> key;
@@ -173,6 +183,16 @@ public interface Holder<T> {
}
}
+ // Leaf start - Optimize isEyeInFluid
+ private TagKey<T>[] boundTagArray() {
+ if (this.tags == null || this.tagArray == null) {
+ throw new IllegalStateException("Tags not bound");
+ } else {
+ return this.tagArray;
+ }
+ }
+ // Leaf end - Optimize isEyeInFluid
+
@Override
public boolean is(TagKey<T> tagKey) {
return this.boundTags().contains(tagKey);
@@ -231,6 +251,7 @@ public interface Holder<T> {
void bindTags(Collection<TagKey<T>> tags) {
this.tags = it.unimi.dsi.fastutil.objects.ReferenceSets.unmodifiable(new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(tags)); // Paper - use reference set because TagKey are interned
+ this.tagArray = this.tags.toArray(new TagKey[0]); // Leaf - Optimize isEyeInFluid
}
@Override
@@ -238,6 +259,13 @@ public interface Holder<T> {
return this.boundTags().stream();
}
+ // Leaf start - Optimize isEyeInFluid
+ @Override
+ public TagKey<T>[] tagArray() {
+ return this.boundTagArray();
+ }
+ // Leaf end - Optimize isEyeInFluid
+
@Override
public String toString() {
return "Reference{" + this.key + "=" + this.value + "}";
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index f2ec8dafb133999bed21eb48b118ab5d382bc962..a26943a7c70ac8b8eb3be5cd1f9838e4fcc6e04e 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -1915,7 +1915,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.awardStat(Stats.SWIM_ONE_CM, rounded);
this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.SWIM); // CraftBukkit - EntityExhaustionEvent // Spigot
}
- } else if (this.isEyeInFluid(FluidTags.WATER)) {
+ } else if (this.isEyeInWater()) { // Leaf - Optimize isEyeInFluid
int rounded = Math.round((float)Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F);
if (rounded > 0) {
this.awardStat(Stats.WALK_UNDER_WATER_ONE_CM, rounded);
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index ab0cf0bff7b477327fd92a20e6c7bc7d62f418d2..ceede6519645cb488ea4152842e00751eef53a6c 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -288,7 +288,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public boolean wasTouchingWater;
protected Object2DoubleMap<TagKey<Fluid>> fluidHeight = new Object2DoubleArrayMap<>(2);
protected boolean wasEyeInWater;
- private final Set<TagKey<Fluid>> fluidOnEyes = new HashSet<>();
+ // Leaf start - Optimize isEyeInFluid
+ // Remove original field since plugin should not direct access to it, and able to
+ // expose potential incompatibility asap.
+ // In paper api, if plugins have custom conditions, then It's more reasonable to
+ // use isEyeInFluid and their own conditions.
+ //private final Set<TagKey<Fluid>> fluidOnEyes = null;
+ private int isInWaterOrLava;
+ // Leaf end - Optimize isEyeInFluid
public int invulnerableTime;
protected boolean firstTick = true;
protected final SynchedEntityData entityData;
@@ -2070,8 +2077,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
private void updateFluidOnEyes() {
- this.wasEyeInWater = this.isEyeInFluid(FluidTags.WATER);
- this.fluidOnEyes.clear();
+ this.wasEyeInWater = this.isInWaterOrLava == 1; // Leaf - Optimize isEyeInFluid
+ this.isInWaterOrLava = 0; // Leaf - Optimize isEyeInFluid - reset cache
double eyeY = this.getEyeY();
if (!(
this.getVehicle() instanceof AbstractBoat abstractBoat
@@ -2083,7 +2090,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
FluidState fluidState = this.level().getFluidState(blockPos);
double d = blockPos.getY() + fluidState.getHeight(this.level(), blockPos);
if (d > eyeY) {
- fluidState.getTags().forEach(this.fluidOnEyes::add);
+ // Leaf start - Optimize isEyeInFluid
+ TagKey<Fluid>[] tags = fluidState.getTagArray();
+ this.isInWaterOrLava = tags.length == 0 ? 0 : tags[0] == FluidTags.WATER ? 1 : 2;
+ // Leaf end - Optimize isEyeInFluid
}
}
}
@@ -2163,9 +2173,25 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
}
+ // Leaf start - Optimize isEyeInFluid
public boolean isEyeInFluid(TagKey<Fluid> fluidTag) {
- return this.fluidOnEyes.contains(fluidTag);
+ if (isInWaterOrLava == 0) {
+ return false;
+ }
+ if (fluidTag == FluidTags.WATER && isInWaterOrLava == 1) {
+ return true;
+ }
+ return fluidTag == FluidTags.LAVA && isInWaterOrLava == 2;
+ }
+
+ public boolean isEyeInWater() {
+ return isInWaterOrLava == 1;
+ }
+
+ public boolean isEyeInLava() {
+ return isInWaterOrLava == 2;
}
+ // Leaf end - Optimize isEyeInFluid
public boolean isInLava() {
return !this.firstTick && this.fluidHeight.getDouble(FluidTags.LAVA) > 0.0;
diff --git a/net/minecraft/world/entity/ExperienceOrb.java b/net/minecraft/world/entity/ExperienceOrb.java
index c8354d46ed909090f7c15f396863bf7d73afcefa..3ee788b172240ccf38cb31385dff13364ccc4142 100644
--- a/net/minecraft/world/entity/ExperienceOrb.java
+++ b/net/minecraft/world/entity/ExperienceOrb.java
@@ -153,7 +153,7 @@ public class ExperienceOrb extends Entity {
} else {
super.tick();
boolean flag = !this.level().noCollision(this.getBoundingBox());
- if (this.isEyeInFluid(FluidTags.WATER)) {
+ if (this.isEyeInWater()) { // Leaf - Optimize isEyeInFluid
this.setUnderwaterMovement();
} else if (!flag) {
this.applyGravity();
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index af9c55edb196beaf2ec403daede16012ac0e8f28..d745fd544263b364c1880220c076be41f269a8b7 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -463,7 +463,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
}
}
- if (this.isEyeInFluid(FluidTags.WATER)
+ if (this.isEyeInWater() // Leaf - Optimize isEyeInFluid
&& !serverLevel1.getBlockState(BlockPos.containing(this.getX(), this.getEyeY(), this.getZ())).is(Blocks.BUBBLE_COLUMN)) {
boolean flag1 = !this.canBreatheUnderwater()
&& !MobEffectUtil.hasWaterBreathing(this)
diff --git a/net/minecraft/world/entity/animal/AbstractFish.java b/net/minecraft/world/entity/animal/AbstractFish.java
index 0002e39e2670ad92849ccc0aada163b174fe1ec2..36b787f5cf4f30589d8b78f86b58553895a1ae51 100644
--- a/net/minecraft/world/entity/animal/AbstractFish.java
+++ b/net/minecraft/world/entity/animal/AbstractFish.java
@@ -182,7 +182,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
@Override
public void vanillaTick() { // Purpur - Ridables
- if (this.fish.isEyeInFluid(FluidTags.WATER)) {
+ if (this.fish.isEyeInWater()) { // Leaf - Optimize isEyeInFluid
this.fish.setDeltaMovement(this.fish.getDeltaMovement().add(0.0, 0.005, 0.0));
}
diff --git a/net/minecraft/world/entity/animal/horse/SkeletonHorse.java b/net/minecraft/world/entity/animal/horse/SkeletonHorse.java
index f6ab6ecc10486694d77905239a82bda4dec94936..8550a8758b1b26e0ddd9ed7f6ae0f167e23d96fe 100644
--- a/net/minecraft/world/entity/animal/horse/SkeletonHorse.java
+++ b/net/minecraft/world/entity/animal/horse/SkeletonHorse.java
@@ -111,7 +111,7 @@ public class SkeletonHorse extends AbstractHorse {
@Override
public SoundEvent getAmbientSound() {
- return this.isEyeInFluid(FluidTags.WATER) ? SoundEvents.SKELETON_HORSE_AMBIENT_WATER : SoundEvents.SKELETON_HORSE_AMBIENT;
+ return this.isEyeInWater() ? SoundEvents.SKELETON_HORSE_AMBIENT_WATER : SoundEvents.SKELETON_HORSE_AMBIENT; // Leaf - Optimize isEyeInFluid
}
@Override
diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java
index 727effd31644432f9da04ee4e3aaa41ce45d6a2e..af9f07f7bcdd75dfa0dff975afcd30476ec5b206 100644
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
@@ -391,7 +391,7 @@ public class Strider extends Animal implements ItemSteerable {
@Override
protected boolean canAddPassenger(Entity passenger) {
- return !this.isVehicle() && !this.isEyeInFluid(FluidTags.LAVA);
+ return !this.isVehicle() && !this.isEyeInLava(); // Leaf - Optimize isEyeInFluid
}
@Override
diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java
index 4b253ae8149f5d9505c5140a00a96d8c8850b1c4..bfb0e3381abb93bea1079fb0d476cf856fca442e 100644
--- a/net/minecraft/world/entity/monster/Witch.java
+++ b/net/minecraft/world/entity/monster/Witch.java
@@ -178,7 +178,7 @@ public class Witch extends Raider implements RangedAttackMob {
}
} else {
Holder<Potion> holder = null;
- if (this.random.nextFloat() < 0.15F && this.isEyeInFluid(FluidTags.WATER) && !this.hasEffect(MobEffects.WATER_BREATHING)) {
+ if (this.random.nextFloat() < 0.15F && this.isEyeInWater() && !this.hasEffect(MobEffects.WATER_BREATHING)) { // Leaf - Optimize isEyeInFluid
holder = Potions.WATER_BREATHING;
} else if (this.random.nextFloat() < 0.15F
&& (this.isOnFire() || this.getLastDamageSource() != null && this.getLastDamageSource().is(DamageTypeTags.IS_FIRE))
diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
index 202dca0a106a1610d8e58b7e9ba0c612998dd868..c27aa33e667abd89c10708f64b172efdf2f07a60 100644
--- a/net/minecraft/world/entity/monster/Zombie.java
+++ b/net/minecraft/world/entity/monster/Zombie.java
@@ -286,7 +286,7 @@ public class Zombie extends Monster {
this.doUnderWaterConversion();
}
} else if (this.convertsInWater()) {
- if (this.isEyeInFluid(FluidTags.WATER)) {
+ if (this.isEyeInWater()) { // Leaf - Optimize isEyeInFluid
this.inWaterTime++;
if (this.inWaterTime >= 600) {
this.startUnderWaterConversion(300);
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 2da9d6a2c12f490bda2cd0b9fb83fa35749f8761..108ef0759e4060fc02d517175731f413c7e2532f 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -398,7 +398,7 @@ public abstract class Player extends LivingEntity {
this.lastItemInMainHand = mainHandItem.copy();
}
- if (!this.isEyeInFluid(FluidTags.WATER) && this.isEquipped(Items.TURTLE_HELMET)) {
+ if (!this.isEyeInWater() && this.isEquipped(Items.TURTLE_HELMET)) { // Leaf - Optimize isEyeInFluid
this.turtleHelmetTick();
}
@@ -438,8 +438,7 @@ public abstract class Player extends LivingEntity {
}
protected boolean updateIsUnderwater() {
- this.wasUnderwater = this.isEyeInFluid(FluidTags.WATER);
- return this.wasUnderwater;
+ return this.wasUnderwater = this.isEyeInWater(); // Leaf - Optimize isEyeInFluid
}
@Override
@@ -845,7 +844,7 @@ public abstract class Player extends LivingEntity {
}
destroySpeed *= (float)this.getAttributeValue(Attributes.BLOCK_BREAK_SPEED);
- if (this.isEyeInFluid(FluidTags.WATER)) {
+ if (this.isEyeInWater()) { // Leaf - Optimize isEyeInFluid
destroySpeed *= (float)this.getAttribute(Attributes.SUBMERGED_MINING_SPEED).getValue();
}
diff --git a/net/minecraft/world/entity/vehicle/AbstractBoat.java b/net/minecraft/world/entity/vehicle/AbstractBoat.java
index d947801b616af5b5dcdcc8bb70b36f97d6a69fdd..678badf7622b81e94c973bed2082fbfafa596b24 100644
--- a/net/minecraft/world/entity/vehicle/AbstractBoat.java
+++ b/net/minecraft/world/entity/vehicle/AbstractBoat.java
@@ -793,7 +793,7 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
@Override
protected boolean canAddPassenger(Entity passenger) {
- return this.getPassengers().size() < this.getMaxPassengers() && !this.isEyeInFluid(FluidTags.WATER);
+ return this.getPassengers().size() < this.getMaxPassengers() && !this.isEyeInWater(); // Leaf - Optimize isEyeInFluid
}
protected int getMaxPassengers() {
diff --git a/net/minecraft/world/level/material/FluidState.java b/net/minecraft/world/level/material/FluidState.java
index 0a5ae623a636923f3bbd3c01974497f39b7c4b62..cc6f2f756c407630aa4e99be329f643c9994af29 100644
--- a/net/minecraft/world/level/material/FluidState.java
+++ b/net/minecraft/world/level/material/FluidState.java
@@ -167,6 +167,12 @@ public final class FluidState extends StateHolder<Fluid, FluidState> implements
return this.owner.builtInRegistryHolder().tags();
}
+ // Leaf start - Optimize isEyeInFluid
+ public TagKey<Fluid>[] getTagArray() {
+ return this.owner.builtInRegistryHolder().tagArray();
+ }
+ // Leaf end - Optimize isEyeInFluid
+
public void entityInside(Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier) {
this.getType().entityInside(level, pos, entity, effectApplier);
}