mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-25 18:09:17 +00:00
Update reduce array allocations
This commit is contained in:
@@ -1,204 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Tue, 3 Jun 2025 15:20:59 +0900
|
||||
Subject: [PATCH] optimize mob spawning
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index f57f8e610dac80b8095bfc0c7e4b22ff5ad6b13c..c1efd558cfbfd2200295ef5755aa496e95deb7d7 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -70,7 +70,9 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
private final Set<ChunkHolder> chunkHoldersToBroadcast = new ReferenceOpenHashSet<>();
|
||||
@Nullable
|
||||
@VisibleForDebug
|
||||
- private NaturalSpawner.SpawnState lastSpawnState;
|
||||
+ private volatile NaturalSpawner.SpawnState lastSpawnState; // Leaf - optimize mob spawning
|
||||
+ private long delayTimeInhabited = 0L; // Leaf - optimize mob spawning
|
||||
+ private long delaySpawn = -1L; // Leaf - optimize mob spawning
|
||||
// Paper start
|
||||
public final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<net.minecraft.world.level.chunk.LevelChunk> fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
public int getFullChunksCount() {
|
||||
@@ -655,13 +657,37 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
filteredSpawningCategories = List.of();
|
||||
}
|
||||
|
||||
- for (LevelChunk levelChunk : chunks) {
|
||||
- ChunkPos pos = levelChunk.getPos();
|
||||
- levelChunk.incrementInhabitedTime(timeInhabited);
|
||||
- if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && lastSpawnState != null && (!org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled || _pufferfish_spawnCountsReady.get()) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot // Pufferfish // Leaf - Don't spawn if lastSpawnState is null
|
||||
- NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState, filteredSpawningCategories); // Pufferfish
|
||||
+ // Leaf start - optimize mob spawning
|
||||
+ var lastSpawnState1 = this.lastSpawnState;
|
||||
+ if (lastSpawnState1 != null && (!org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled || _pufferfish_spawnCountsReady.get())) {
|
||||
+ long sumTimeInhabited = timeInhabited + delayTimeInhabited;
|
||||
+ long time = level.getGameTime();
|
||||
+ for (LevelChunk levelChunk : chunks) {
|
||||
+ ChunkPos pos = levelChunk.getPos();
|
||||
+ levelChunk.incrementInhabitedTime(sumTimeInhabited);
|
||||
+ if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot
|
||||
+ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories, time); // Pufferfish
|
||||
+ }
|
||||
+ }
|
||||
+ if (delaySpawn != -1L) {
|
||||
+ time = delaySpawn;
|
||||
+ for (LevelChunk levelChunk : chunks) {
|
||||
+ ChunkPos pos = levelChunk.getPos();
|
||||
+ if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot
|
||||
+ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories, time); // Pufferfish
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+ delaySpawn = -1L;
|
||||
+ delayTimeInhabited = 0L;
|
||||
+ } else {
|
||||
+ // unlikely
|
||||
+ delayTimeInhabited += timeInhabited;
|
||||
+ delaySpawn = level.getGameTime();
|
||||
+ }
|
||||
+ // Leaf end - optimize mob spawning
|
||||
|
||||
+ for (LevelChunk levelChunk : chunks) { // Leaf - optimize mob spawning - split to 2 loop
|
||||
if (true) { // Paper - rewrite chunk system
|
||||
this.level.tickChunk(levelChunk, _int);
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 9b37b763c6555705f3e256010f508b5a0c2cdb66..bde7008e14a3b4c0a37a94a4890e2f7fa1ce2466 100644
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -155,7 +155,13 @@ public final class NaturalSpawner {
|
||||
return list;
|
||||
}
|
||||
|
||||
+ @Deprecated(forRemoval = true) // Leaf - optimize mob spawning
|
||||
public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List<MobCategory> categories) {
|
||||
+ // Leaf start - optimize mob spawning
|
||||
+ spawnForChunk(level, chunk, spawnState, categories, level.getGameTime());
|
||||
+ }
|
||||
+ public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List<MobCategory> categories, long gameTime) {
|
||||
+ // Leaf end - optimize mob spawning
|
||||
for (MobCategory mobCategory : categories) {
|
||||
// Paper start - Optional per player mob spawns
|
||||
final boolean canSpawn;
|
||||
@@ -174,7 +180,7 @@ public final class NaturalSpawner {
|
||||
}
|
||||
// Paper end - throttle failed spawn attempts
|
||||
if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
- spawnThisTick = ticksPerSpawnTmp != 0 && level.getGameTime() % ticksPerSpawn == 0; // Paper - throttle failed spawn attempts
|
||||
+ spawnThisTick = ticksPerSpawnTmp != 0 && gameTime % ticksPerSpawn == 0; // Paper - throttle failed spawn attempts // Leaf - optimize mob spawning
|
||||
limit = level.getWorld().getSpawnLimit(spawnCategory);
|
||||
}
|
||||
|
||||
@@ -238,12 +244,14 @@ public final class NaturalSpawner {
|
||||
// Paper end - throttle failed spawn attempts
|
||||
) {
|
||||
// Paper end - Optional per player mob spawns
|
||||
- BlockPos randomPosWithin = getRandomPosWithin(level, chunk);
|
||||
- if (randomPosWithin.getY() >= level.getMinY() + 1) {
|
||||
- return spawnCategoryForPosition(category, level, chunk, randomPosWithin, filter, callback, maxSpawns, trackEntity, false); // Paper - Optional per player mob spawns // Paper - throttle failed spawn attempts
|
||||
+ // Leaf start - optimize mob spawning
|
||||
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
+ mutableRandomPosWithin(pos, level, chunk);
|
||||
+ if (pos.getY() < level.getMinY() + 1) {
|
||||
+ return 0;
|
||||
}
|
||||
-
|
||||
- return 0; // Paper - throttle failed spawn attempts
|
||||
+ 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
|
||||
}
|
||||
|
||||
@VisibleForDebug
|
||||
@@ -275,31 +283,55 @@ public final class NaturalSpawner {
|
||||
StructureManager structureManager = level.structureManager();
|
||||
ChunkGenerator generator = level.getChunkSource().getGenerator();
|
||||
int y = pos.getY();
|
||||
+ 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
|
||||
- BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
+ 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
|
||||
|
||||
+ // Leaf start - optimize mob spawning
|
||||
+ long rand = level.random.nextLong();
|
||||
+ int bits = 0;
|
||||
for (int i1 = 0; i1 < 3; i1++) {
|
||||
- int x = pos.getX();
|
||||
- int z = pos.getZ();
|
||||
- int i2 = 6;
|
||||
+ int x = posX;
|
||||
+ int z = posZ;
|
||||
MobSpawnSettings.SpawnerData spawnerData = null;
|
||||
SpawnGroupData spawnGroupData = null;
|
||||
- int ceil = Mth.ceil(level.random.nextFloat() * 4.0F);
|
||||
+ int ceil = (int) ((rand & 0x3L) + 1L);
|
||||
+ bits += 2;
|
||||
int i3 = 0;
|
||||
|
||||
for (int i4 = 0; i4 < ceil; i4++) {
|
||||
- x += level.random.nextInt(6) - level.random.nextInt(6);
|
||||
- z += level.random.nextInt(6) - level.random.nextInt(6);
|
||||
+ int rand1=0,rand2=0,rand3=0,rand4=0,valuesNeeded=4;
|
||||
+ while (valuesNeeded > 0) {
|
||||
+ if (bits > 61) {
|
||||
+ rand = level.random.nextLong();
|
||||
+ bits = 0;
|
||||
+ }
|
||||
+ int threeBits = (int) ((rand >>> bits) & 0x7L);
|
||||
+ bits += 3;
|
||||
+ if (threeBits != 7 && threeBits != 6) {
|
||||
+ switch (valuesNeeded) {
|
||||
+ case 1 -> rand4 = threeBits;
|
||||
+ case 2 -> rand3 = threeBits;
|
||||
+ case 3 -> rand2 = threeBits;
|
||||
+ case 4 -> rand1 = threeBits;
|
||||
+ }
|
||||
+ valuesNeeded--;
|
||||
+ }
|
||||
+ }
|
||||
+ x += rand1 - rand2;
|
||||
+ z += rand3 - rand4;
|
||||
+ // Leaf end - optimize mob spawning
|
||||
mutableBlockPos.set(x, y, z);
|
||||
double d = x + 0.5;
|
||||
double d1 = z + 0.5;
|
||||
Player nearestPlayer = level.getNearestPlayer(d, y, d1, -1.0, level.purpurConfig.mobSpawningIgnoreCreativePlayers); // Purpur - mob spawning option to ignore creative players
|
||||
if (nearestPlayer != null) {
|
||||
double d2 = nearestPlayer.distanceToSqr(d, y, d1);
|
||||
- if (level.isLoadedAndInBounds(mutableBlockPos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn
|
||||
+ if (level.getWorldBorder().isWithinBounds(mutableBlockPos) && (chunk.getPos().longKey == ChunkPos.asLong(mutableBlockPos) || level.getChunkIfLoadedImmediately(mutableBlockPos.getX() >> 4, mutableBlockPos.getZ() >> 4) != null) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn // Leaf - optimize mob spawning
|
||||
if (spawnerData == null) {
|
||||
Optional<MobSpawnSettings.SpawnerData> randomSpawnMobAt = getRandomSpawnMobAt(
|
||||
level, structureManager, generator, category, level.random, mutableBlockPos
|
||||
@@ -368,8 +400,8 @@ public final class NaturalSpawner {
|
||||
|
||||
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel level, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double distance) {
|
||||
return !(distance <= 576.0)
|
||||
- && !level.getSharedSpawnPos().closerToCenterThan(new Vec3(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5), 24.0)
|
||||
- && (Objects.equals(new ChunkPos(pos), chunk.getPos()) || level.isNaturalSpawningAllowed(pos));
|
||||
+ && !(level.getSharedSpawnPos().distToCenterSqr(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5) < 576.0) // Leaf - optimize mob spawning
|
||||
+ && (ChunkPos.asLong(pos) == chunk.getPos().longKey || level.isNaturalSpawningAllowed(pos)); // Leaf - optimize mob spawning
|
||||
}
|
||||
|
||||
// Paper start - PreCreatureSpawnEvent
|
||||
@@ -474,6 +506,17 @@ public final class NaturalSpawner {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Leaf start - optimize mob spawning
|
||||
+ private static void mutableRandomPosWithin(BlockPos.MutableBlockPos pos1, Level level, LevelChunk chunk) {
|
||||
+ ChunkPos pos = chunk.getPos();
|
||||
+ int randomX = pos.getMinBlockX() + level.random.nextInt(16);
|
||||
+ int randomZ = pos.getMinBlockZ() + level.random.nextInt(16);
|
||||
+ int surfaceY = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, randomX, randomZ) + 1;
|
||||
+ int randomY = Mth.randomBetweenInclusive(level.random, level.getMinY(), surfaceY);
|
||||
+ pos1.set(randomX, randomY, randomZ);
|
||||
+ }
|
||||
+ // Leaf end - optimize mob spawning
|
||||
+
|
||||
private static BlockPos getRandomPosWithin(Level level, LevelChunk chunk) {
|
||||
ChunkPos pos = chunk.getPos();
|
||||
int i = pos.getMinBlockX() + level.random.nextInt(16);
|
||||
@@ -6,6 +6,18 @@ Subject: [PATCH] Reduce array allocations
|
||||
License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
Gale - https://galemc.org
|
||||
|
||||
Enum's values returns anew array copy of the enums, this behavior is defined in
|
||||
`src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java#visitEnumDef`
|
||||
|
||||
This is a defensive programming strategy to prevent enums from being modified. However,
|
||||
copying is unnecessary if we only have read calls.
|
||||
So we can cache the values result to avoid useless allocations.
|
||||
|
||||
Cached as the array since it does not create iterator on the enhanced for loop,
|
||||
But the list does, and may spend more time than iterating using the array.
|
||||
|
||||
The JMH benchmark of this patch can be found in SunBox's `CachedEnumValuesForLoop`
|
||||
|
||||
This patch is based on the following patch:
|
||||
"reduce allocs"
|
||||
By: Simon Gardling <titaniumtown@gmail.com>
|
||||
@@ -250,7 +262,7 @@ index 0e44397c9d53ff30a96c9e8e392a363fa9ae0c55..dbf31389f0e9796c80afbffddf6a20cb
|
||||
private final EquipmentSlot.Type type;
|
||||
private final int index;
|
||||
diff --git a/net/minecraft/world/entity/EquipmentSlotGroup.java b/net/minecraft/world/entity/EquipmentSlotGroup.java
|
||||
index 381e0a1c0af7e339713ed1df1c2f21121c1bbd0f..1ebcab2ee9898a618ad76b18491be19859629192 100644
|
||||
index 381e0a1c0af7e339713ed1df1c2f21121c1bbd0f..4e847c3f9d761da5dda11dec60582d9d9e630b37 100644
|
||||
--- a/net/minecraft/world/entity/EquipmentSlotGroup.java
|
||||
+++ b/net/minecraft/world/entity/EquipmentSlotGroup.java
|
||||
@@ -24,6 +24,7 @@ public enum EquipmentSlotGroup implements StringRepresentable, Iterable<Equipmen
|
||||
@@ -261,15 +273,6 @@ index 381e0a1c0af7e339713ed1df1c2f21121c1bbd0f..1ebcab2ee9898a618ad76b18491be198
|
||||
public static final IntFunction<EquipmentSlotGroup> BY_ID = ByIdMap.continuous(
|
||||
equipmentSlotGroup -> equipmentSlotGroup.id, values(), ByIdMap.OutOfBoundsStrategy.ZERO
|
||||
);
|
||||
@@ -38,7 +39,7 @@ public enum EquipmentSlotGroup implements StringRepresentable, Iterable<Equipmen
|
||||
this.id = id;
|
||||
this.key = key;
|
||||
this.predicate = predicate;
|
||||
- this.slots = EquipmentSlot.VALUES.stream().filter(predicate).toList();
|
||||
+ this.slots = EquipmentSlot.VALUES.stream().filter(predicate).toList(); // Gale - JettPack - reduce array allocations
|
||||
}
|
||||
|
||||
private EquipmentSlotGroup(final int id, final String key, final EquipmentSlot slot) {
|
||||
diff --git a/net/minecraft/world/entity/EquipmentTable.java b/net/minecraft/world/entity/EquipmentTable.java
|
||||
index b383836c200ca9f7bd84639367aa81b57868fb25..3af4a6dcc81afaf2860325fe5852c9a941f216d4 100644
|
||||
--- a/net/minecraft/world/entity/EquipmentTable.java
|
||||
@@ -283,6 +286,112 @@ index b383836c200ca9f7bd84639367aa81b57868fb25..3af4a6dcc81afaf2860325fe5852c9a9
|
||||
}
|
||||
|
||||
private static Map<EquipmentSlot, Float> createForAllSlots(List<EquipmentSlot> equipmentSlots, float dropChance) {
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index 395ebf0a5fa14d9ff43b2d2e8e63aeaaf4612443..c6f87ee9b7c2b0bfc2d459a86b60ad2eaa23b594 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3358,7 +3358,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
Map<org.bukkit.inventory.EquipmentSlot, io.papermc.paper.event.entity.EntityEquipmentChangedEvent.EquipmentChange> equipmentChanges = null;
|
||||
// Paper end - EntityEquipmentChangedEvent
|
||||
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
ItemStack itemStack = this.lastEquipmentItems.get(equipmentSlot);
|
||||
ItemStack itemBySlot = this.getItemBySlot(equipmentSlot);
|
||||
if (this.equipmentHasChanged(itemStack, itemBySlot)) {
|
||||
@@ -3630,7 +3630,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
|
||||
public boolean canGlide() {
|
||||
if (!this.onGround() && !this.isPassenger() && !this.hasEffect(MobEffects.LEVITATION)) {
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
if (canGlideUsing(this.getItemBySlot(equipmentSlot), equipmentSlot)) {
|
||||
return true;
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||
index 4d4b58b684ca115f4d8f672362d4c8252ef9481a..939d8c53a8eb445c1b5b0c65842ecb64ad317252 100644
|
||||
--- a/net/minecraft/world/entity/Mob.java
|
||||
+++ b/net/minecraft/world/entity/Mob.java
|
||||
@@ -338,7 +338,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
if (this.xpReward > 0) {
|
||||
int i = this.xpReward;
|
||||
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
if (equipmentSlot.canIncreaseExperience()) {
|
||||
ItemStack itemBySlot = this.getItemBySlot(equipmentSlot);
|
||||
if (!itemBySlot.isEmpty() && this.dropChances.byEquipment(equipmentSlot) <= 1.0F) {
|
||||
@@ -950,7 +950,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
protected void dropCustomDeathLoot(ServerLevel level, DamageSource damageSource, boolean recentlyHit) {
|
||||
super.dropCustomDeathLoot(level, damageSource, recentlyHit);
|
||||
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
if (this.shouldSkipLoot(equipmentSlot)) continue; // Paper
|
||||
ItemStack itemBySlot = this.getItemBySlot(equipmentSlot);
|
||||
float f = this.dropChances.byEquipment(equipmentSlot);
|
||||
@@ -994,7 +994,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
public Set<EquipmentSlot> dropPreservedEquipment(ServerLevel level, Predicate<ItemStack> filter) {
|
||||
Set<EquipmentSlot> set = new HashSet<>();
|
||||
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
ItemStack itemBySlot = this.getItemBySlot(equipmentSlot);
|
||||
if (!itemBySlot.isEmpty()) {
|
||||
if (!filter.test(itemBySlot)) {
|
||||
@@ -1122,7 +1122,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
protected void populateDefaultEquipmentEnchantments(ServerLevelAccessor level, RandomSource random, DifficultyInstance difficulty) {
|
||||
this.enchantSpawnedWeapon(level, random, difficulty);
|
||||
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
if (equipmentSlot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR) {
|
||||
this.enchantSpawnedArmor(level, random, equipmentSlot, difficulty);
|
||||
}
|
||||
@@ -1539,7 +1539,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
protected void removeAfterChangingDimensions() {
|
||||
super.removeAfterChangingDimensions();
|
||||
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
ItemStack itemBySlot = this.getItemBySlot(equipmentSlot);
|
||||
if (!itemBySlot.isEmpty()) {
|
||||
itemBySlot.setCount(0);
|
||||
diff --git a/net/minecraft/world/entity/decoration/ArmorStand.java b/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
index 5ee368580d878a3845349c3d50cc0dc549c42cab..9952e84dd94b8773c5ba8fcc4526e7714ebc2136 100644
|
||||
--- a/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
+++ b/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
@@ -456,7 +456,7 @@ public class ArmorStand extends LivingEntity {
|
||||
this.playBrokenSound();
|
||||
// this.dropAllDeathLoot(level, damageSource); // CraftBukkit - moved down
|
||||
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
ItemStack itemStack = this.equipment.get(equipmentSlot); // Paper - move equipment removal past event call
|
||||
if (!itemStack.isEmpty()) {
|
||||
this.drops.add(new DefaultDrop(itemStack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly}
|
||||
@@ -465,7 +465,7 @@ public class ArmorStand extends LivingEntity {
|
||||
// Paper start - move equipment removal past event call
|
||||
org.bukkit.event.entity.EntityDeathEvent event = this.dropAllDeathLoot(level, damageSource);
|
||||
if (!event.isCancelled()) {
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
this.equipment.set(equipmentSlot, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
|
||||
index e5e08dbefead90e9fe2bb05e4f0257f7aa4c0686..5160c349f1ace36d6de11f23e0f957f37fc19165 100644
|
||||
--- a/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/net/minecraft/world/entity/player/Player.java
|
||||
@@ -413,7 +413,7 @@ public abstract class Player extends LivingEntity {
|
||||
}
|
||||
|
||||
private boolean isEquipped(Item item) {
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
ItemStack itemBySlot = this.getItemBySlot(equipmentSlot);
|
||||
Equippable equippable = itemBySlot.get(DataComponents.EQUIPPABLE);
|
||||
if (itemBySlot.is(item) && equippable != null && equippable.slot() == equipmentSlot) {
|
||||
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
||||
index da16f4831c875e07c25d7ed041bed493db614658..951c86278e8cb5cd801a5db2ebfabef8c6d813ef 100644
|
||||
--- a/net/minecraft/world/item/ItemStack.java
|
||||
@@ -309,6 +418,41 @@ index bfda76974ea8d4397e2c2ebf5bdcb5d7e5f0bab5..cabbc93409ca99180d115e2f23419ee1
|
||||
} else {
|
||||
String[] strings = new String[pattern.size() - i3 - i2];
|
||||
|
||||
diff --git a/net/minecraft/world/item/enchantment/Enchantment.java b/net/minecraft/world/item/enchantment/Enchantment.java
|
||||
index 7a620eb92b1e672cedd72ec4d986c01eba337686..0460da0124d2c48b7fed45fa182537fd8059135d 100644
|
||||
--- a/net/minecraft/world/item/enchantment/Enchantment.java
|
||||
+++ b/net/minecraft/world/item/enchantment/Enchantment.java
|
||||
@@ -109,7 +109,7 @@ public record Enchantment(Component description, Enchantment.EnchantmentDefiniti
|
||||
public Map<EquipmentSlot, ItemStack> getSlotItems(LivingEntity entity) {
|
||||
Map<EquipmentSlot, ItemStack> map = Maps.newEnumMap(EquipmentSlot.class);
|
||||
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
if (this.matchingSlot(equipmentSlot)) {
|
||||
ItemStack itemBySlot = entity.getItemBySlot(equipmentSlot);
|
||||
if (!itemBySlot.isEmpty()) {
|
||||
diff --git a/net/minecraft/world/item/enchantment/EnchantmentHelper.java b/net/minecraft/world/item/enchantment/EnchantmentHelper.java
|
||||
index 66234431b265e0596275ca468cd40f8da98c22e2..b20415b47e209aedbc60ff17238e575dfe33849a 100644
|
||||
--- a/net/minecraft/world/item/enchantment/EnchantmentHelper.java
|
||||
+++ b/net/minecraft/world/item/enchantment/EnchantmentHelper.java
|
||||
@@ -153,7 +153,7 @@ public class EnchantmentHelper {
|
||||
}
|
||||
|
||||
private static void runIterationOnEquipment(LivingEntity entity, EnchantmentHelper.EnchantmentInSlotVisitor visitor) {
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
runIterationOnItem(entity.getItemBySlot(equipmentSlot), equipmentSlot, entity, visitor);
|
||||
}
|
||||
}
|
||||
@@ -467,7 +467,7 @@ public class EnchantmentHelper {
|
||||
public static Optional<EnchantedItemInUse> getRandomItemWith(DataComponentType<?> componentType, LivingEntity entity, Predicate<ItemStack> filter) {
|
||||
List<EnchantedItemInUse> list = new ArrayList<>();
|
||||
|
||||
- for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
|
||||
+ for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
ItemStack itemBySlot = entity.getItemBySlot(equipmentSlot);
|
||||
if (filter.test(itemBySlot)) {
|
||||
ItemEnchantments itemEnchantments = itemBySlot.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index a0254e85fccebb66ce02bd58f9d461addd8ad73d..1f7b3db02e59c4cbc93bc0e4e42bd20e0031c4bd 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
|
||||
@@ -9,7 +9,7 @@ Gale - https://galemc.org
|
||||
The JMH benchmark of this patch can be found in SunBox's `RecordHashCode`
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/collisions/util/FluidOcclusionCacheKey.java b/ca/spottedleaf/moonrise/patches/collisions/util/FluidOcclusionCacheKey.java
|
||||
index cf9ffdeff6bf0b62a45f7a44dbfe0dd7d17dc4f4..f1480625eaece1553d4a96ec54138a463a6fc1ca 100644
|
||||
index cf9ffdeff6bf0b62a45f7a44dbfe0dd7d17dc4f4..fcff01c84d611a75dbf79b1644092516c7cfb0bc 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/collisions/util/FluidOcclusionCacheKey.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/collisions/util/FluidOcclusionCacheKey.java
|
||||
@@ -3,5 +3,58 @@ package ca.spottedleaf.moonrise.patches.collisions.util;
|
||||
@@ -17,7 +17,7 @@ index cf9ffdeff6bf0b62a45f7a44dbfe0dd7d17dc4f4..f1480625eaece1553d4a96ec54138a46
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
-public record FluidOcclusionCacheKey(BlockState first, BlockState second, Direction direction, boolean result) {
|
||||
+// Gale start - Lithium - cache FluidOcclusionCacheKey hash
|
||||
+// Gale start - cache FluidOcclusionCacheKey hash
|
||||
+public final class FluidOcclusionCacheKey {
|
||||
+ private final BlockState first;
|
||||
+ private final BlockState second;
|
||||
@@ -70,5 +70,5 @@ index cf9ffdeff6bf0b62a45f7a44dbfe0dd7d17dc4f4..f1480625eaece1553d4a96ec54138a46
|
||||
+ "direction=" + direction + ", " +
|
||||
+ "result=" + result + ']';
|
||||
+ }
|
||||
+ // Gale end - Lithium - cache FluidOcclusionCacheKey hash
|
||||
+ // Gale end - cache FluidOcclusionCacheKey hash
|
||||
}
|
||||
|
||||
@@ -6,6 +6,18 @@ Subject: [PATCH] Reduce array allocations
|
||||
License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
Gale - https://galemc.org
|
||||
|
||||
Enum's values returns anew array copy of the enums, this behavior is defined in
|
||||
`src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java#visitEnumDef`
|
||||
|
||||
This is a defensive programming strategy to prevent enums from being modified. However,
|
||||
copying is unnecessary if we only have read calls.
|
||||
So we can cache the values result to avoid useless allocations.
|
||||
|
||||
Cached as the array since it does not create iterator on the enhanced for loop,
|
||||
But the list does, and may spend more time than iterating using the array.
|
||||
|
||||
The JMH benchmark of this patch can be found in SunBox's `CachedEnumValuesForLoop`
|
||||
|
||||
This patch is based on the following patch:
|
||||
"reduce allocs"
|
||||
By: Simon Gardling <titaniumtown@gmail.com>
|
||||
@@ -98,7 +110,7 @@ index db92261a6cb3758391108361096417c61bc82cdc..1a14fddb36ca3c14d243304db629d0c5
|
||||
|
||||
public SortedList(final E[] elements, final Comparator<? super E> comparator) {
|
||||
diff --git a/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java b/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java
|
||||
index af480008adc07c63344d625101d1bf42fab96b5d..8c9609b95cf27b6316c48a554b2c508aa527b964 100644
|
||||
index f37adc5dcad50a3e313c63ebee795161b4fa8b8f..948460266c6fd40b7b5197f81aa5ed90dc54b66a 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java
|
||||
@@ -178,7 +178,7 @@ public class PaperCommands implements Commands, PaperRegistrar<LifecycleEventOwn
|
||||
@@ -124,7 +136,7 @@ index 58ca24715eafd1ac3cc9657b1cc235049d69bb59..acb764b71bb3e8f159a758002f7d1077
|
||||
return true;
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java
|
||||
index 4abe58077fae4e68cceda9624fed013bca1d6f22..72aa906ccf64dd9be085728a897f323ab0822eba 100644
|
||||
index 4abe58077fae4e68cceda9624fed013bca1d6f22..dbbff2c73ae995f847b470a1e0853583cc377dc4 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java
|
||||
@@ -165,7 +165,7 @@ public class CraftEntityEquipment implements EntityEquipment {
|
||||
@@ -132,7 +144,7 @@ index 4abe58077fae4e68cceda9624fed013bca1d6f22..72aa906ccf64dd9be085728a897f323a
|
||||
@Override
|
||||
public void clear() {
|
||||
- for (net.minecraft.world.entity.EquipmentSlot slot : net.minecraft.world.entity.EquipmentSlot.values()) {
|
||||
+ for (net.minecraft.world.entity.EquipmentSlot slot : net.minecraft.world.entity.EquipmentSlot.VALUES) { // Gale - JettPack - reduce array allocations
|
||||
+ for (net.minecraft.world.entity.EquipmentSlot slot : net.minecraft.world.entity.EquipmentSlot.VALUES_ARRAY) { // Gale - JettPack - reduce array allocations
|
||||
this.setEquipment(slot, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user