Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bunch of side perf improvements #217

Draft
wants to merge 66 commits into
base: ver/1.21.4
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
a504b6f
Fix TE Lag
Taiyou06 Feb 7, 2025
9f11f4d
Sepals Rearrange the attackable conditions
Taiyou06 Feb 7, 2025
24df8b7
Cache ItemStack max stack size
Taiyou06 Feb 7, 2025
5995636
fix build
Taiyou06 Feb 7, 2025
2c58199
extra: Skip dirty stats copy when requesting player stats
Taiyou06 Feb 7, 2025
d473e2d
extra: Reset dirty flag when loading maps from the disk
Taiyou06 Feb 7, 2025
a32e61a
extra: Supporting block cache
Taiyou06 Feb 8, 2025
0068ab8
extra: Avoid useless deque clear on - credit: @MachineBreaker
Taiyou06 Feb 8, 2025
34c1344
experimental/draft: Optimize SortedArraySet
Taiyou06 Feb 8, 2025
f40f313
experimental/draft: Simplify SortedArraySet - sometime complex stuff …
Taiyou06 Feb 8, 2025
0d2afaf
extra: Change maps/sets in brain + remove streams from villagers
Taiyou06 Feb 8, 2025
b08fcdc
extra: Remove 'copyOf' from Baby Villager Sensor
Taiyou06 Feb 8, 2025
4ab9620
experimental: Rewrite trigger in SimpleCriterionTrigger
Taiyou06 Feb 9, 2025
21f309b
[ci skip] fix comments
Taiyou06 Feb 9, 2025
8c782ac
Faster setter for SimpleCriterionTrigger
Taiyou06 Feb 9, 2025
e90bc06
extra: Cache and optimize fluidOnEyes
Taiyou06 Feb 9, 2025
d1f8d6f
Merge branch 'refs/heads/ver/1.21.4' into tramontane-stuff
Taiyou06 Feb 9, 2025
6c6bcf7
Sync changes
Taiyou06 Feb 9, 2025
142294b
[ci skip] cleanup
Dreeam-qwq Feb 9, 2025
f445da9
extra: QuadTree implementation for isChunkNearPlayer
Taiyou06 Feb 9, 2025
f606719
Merge branch 'ver/1.21.4' into tramontane-stuff
Dreeam-qwq Feb 10, 2025
cf66d42
[ci skip] cleanup
Dreeam-qwq Feb 10, 2025
885ab02
[ci skip] cleanup
Dreeam-qwq Feb 10, 2025
6d73657
[ci skip] clean up
Dreeam-qwq Feb 10, 2025
b952f00
[ci skip] cleanup
Dreeam-qwq Feb 10, 2025
683e265
Only player pushable
Dreeam-qwq Feb 10, 2025
0e579a5
Store chunkPos with keys
Taiyou06 Feb 10, 2025
a1d53d0
[ci skip] cleanup
Dreeam-qwq Feb 10, 2025
b8d2e0f
[ci skip] cleanup
Dreeam-qwq Feb 11, 2025
7f662a2
cleanup
Dreeam-qwq Feb 11, 2025
5b3ab9d
Merge branch 'ver/1.21.4' into tramontane-stuff
Dreeam-qwq Feb 11, 2025
a9cc733
rebuild patches
Dreeam-qwq Feb 11, 2025
d39ef4b
cache some more stuff
Taiyou06 Feb 11, 2025
f475093
extra: optimize collectTickingChunks
Taiyou06 Feb 11, 2025
7bb0b19
remove quadTree optimization for now (will open a new PR just for that)
Taiyou06 Feb 11, 2025
0a309fe
temp: Lazily optimize isChunkNearPlayer
Taiyou06 Feb 11, 2025
e643643
Merge branch 'ver/1.21.4' into tramontane-stuff
Dreeam-qwq Feb 12, 2025
abbe9d0
Merge branch 'ver/1.21.4' into tramontane-stuff
Dreeam-qwq Feb 12, 2025
d32e9c6
Inline filter & merge as a single loop
Dreeam-qwq Feb 12, 2025
802cb5c
[ci skip] Add diff on change
Dreeam-qwq Feb 12, 2025
49bd9ca
extra: optimize everything but the testing itself on getEntities
Taiyou06 Feb 12, 2025
ff3a466
[ci skip] cleanup
Dreeam-qwq Feb 13, 2025
8e9ebd9
Optimize chunkUnloadQueue
Dreeam-qwq Feb 13, 2025
2053803
Remove iterators from inventory
Dreeam-qwq Feb 13, 2025
e2ef94c
[ci skip] Add TODOs
Dreeam-qwq Feb 13, 2025
e20fcbb
i hate programming
Taiyou06 Feb 13, 2025
8bccbbd
remove forEach
Taiyou06 Feb 13, 2025
001c28a
extra: Alternative Brain Behaviour
Taiyou06 Feb 14, 2025
ced4f93
remove: opt getEntities + cache fluidOnEyes
Taiyou06 Feb 14, 2025
4c408b3
extra: Improve checkDespawn - credits: @kidofcubes
Taiyou06 Feb 14, 2025
03486cf
extra: Improve pushEntity and getEntities
Taiyou06 Feb 14, 2025
d9dd4fa
yeet this
Taiyou06 Feb 15, 2025
8e6eb96
VERY EXPERIMENTAL: getEntities Optimization
Taiyou06 Feb 15, 2025
469e80b
fix bunch of issues from getEntities patch
Taiyou06 Feb 15, 2025
d33c0df
extra: slightly optimize getNearestPlayer - credits: @kidofcubes
Taiyou06 Feb 15, 2025
e2fdf06
drop a patch for now (will open a new pr)
Taiyou06 Feb 15, 2025
f2f722f
move these to a new branch
Taiyou06 Feb 15, 2025
94a1b03
fix and optimize checkDespawn patches
Taiyou06 Feb 16, 2025
e34c1ed
Merge branch 'ver/1.21.4' into tramontane-stuff
Dreeam-qwq Feb 17, 2025
b09378a
Rebuild Patches
Dreeam-qwq Feb 17, 2025
d5acf18
[ci skip] Update benchmark
Dreeam-qwq Feb 18, 2025
7c62b8a
[ci skip] cleanup
Dreeam-qwq Feb 18, 2025
a80dc6b
Drop
Dreeam-qwq Feb 18, 2025
a4342ed
[ci skip] Drop
Dreeam-qwq Feb 20, 2025
6955ec7
Merge branch 'ver/1.21.4' into tramontane-stuff
Dreeam-qwq Feb 20, 2025
104099f
Rebuild
Dreeam-qwq Feb 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build-data/leaf.at
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ protected-f net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase$
public net.minecraft.util.Mth SIN
public net.minecraft.world.entity.Entity updateInWaterStateAndDoWaterCurrentPushing()V
public net.minecraft.world.entity.LivingEntity canGlide()Z
public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities lineOfSightTest
public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities nearbyEntities
public net.minecraft.world.entity.decoration.ArmorStand noTickEquipmentDirty
public net.minecraft.world.entity.monster.Shulker MAX_SCALE
public net.minecraft.world.entity.player.Player canGlide()Z
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Taiyou06 <[email protected]>
Date: Sun, 9 Feb 2025 01:36:24 +0100
Subject: [PATCH] Replace criterion listener map with optimized collection


diff --git a/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
index 4b2ae046413146b11912e7aa4a9a3d643de6afd1..6a4889d4ba90c1995e15c0daa6bb52682ec87eb4 100644
--- a/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
+++ b/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
@@ -19,7 +19,7 @@ public abstract class SimpleCriterionTrigger<T extends SimpleCriterionTrigger.Si

@Override
public final void addPlayerListener(PlayerAdvancements playerAdvancements, CriterionTrigger.Listener<T> listener) {
- playerAdvancements.criterionData.computeIfAbsent(this, managerx -> Sets.newHashSet()).add(listener); // Paper - fix PlayerAdvancements leak
+ playerAdvancements.criterionData.computeIfAbsent(this, managerx -> new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>()).add(listener); // Paper - fix PlayerAdvancements leak // Leaf - Replace criterion listener map with optimized collection
}

@Override
@@ -43,7 +43,7 @@ public abstract class SimpleCriterionTrigger<T extends SimpleCriterionTrigger.Si
Set<CriterionTrigger.Listener<T>> set = (Set) advancements.criterionData.get(this); // Paper - fix PlayerAdvancements leak
if (set != null && !set.isEmpty()) {
LootContext lootContext = null; // EntityPredicate.createContext(player, player); // Paper - Perf: lazily create LootContext for criterions
- List<CriterionTrigger.Listener<T>> list = null;
+ it.unimi.dsi.fastutil.objects.ObjectArrayList<CriterionTrigger.Listener<T>> list = null; // Leaf - Replace criterion listener map with optimized collection

for (CriterionTrigger.Listener<T> listener : set) {
T simpleInstance = listener.trigger();
@@ -51,7 +51,7 @@ public abstract class SimpleCriterionTrigger<T extends SimpleCriterionTrigger.Si
Optional<ContextAwarePredicate> optional = simpleInstance.player();
if (optional.isEmpty() || optional.get().matches(lootContext = (lootContext == null ? EntityPredicate.createContext(player, player) : lootContext))) { // Paper - Perf: lazily create LootContext for criterions
if (list == null) {
- list = Lists.newArrayList();
+ list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // Leaf - Replace criterion listener map with optimized collection
}

list.add(listener);
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Taiyou06 <[email protected]>
Date: Fri, 7 Feb 2025 21:41:51 +0100
Subject: [PATCH] Cache ItemStack max stack size

TODO: check this, fix get max stack size

diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index fd7c1e800cbd4919a1a47f6c468c8776535bd028..fdd7e89bacc98e23f067ba17d0bd93ee84a388cb 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -194,6 +194,7 @@ public final class ItemStack implements DataComponentHolder, net.caffeinemc.mods
private static final Logger LOGGER = LogUtils.getLogger();
public static final ItemStack EMPTY = new ItemStack((Void)null);
private static final Component DISABLED_ITEM_TOOLTIP = Component.translatable("item.disabled").withStyle(ChatFormatting.RED);
+ private int maxStackSize;
private int count;
private int popTime;
@Deprecated
@@ -289,11 +290,13 @@ public final class ItemStack implements DataComponentHolder, net.caffeinemc.mods
this.count = count;
this.components = components;
this.getItem().verifyComponentsAfterLoad(this);
+ this.maxStackSize = getMaxStackSizeInternal(); // Leaf - Cache ItemStack max stack size
}

private ItemStack(@Nullable Void unused) {
this.item = null;
this.components = new PatchedDataComponentMap(DataComponentMap.EMPTY);
+ this.maxStackSize = 1; // Leaf - Cache ItemStack max stack size - taken from ItemStack#isEmpty
}

public static DataResult<Unit> validateComponents(DataComponentMap components) {
@@ -619,9 +622,15 @@ public final class ItemStack implements DataComponentHolder, net.caffeinemc.mods
}

public int getMaxStackSize() {
- return this.getOrDefault(DataComponents.MAX_STACK_SIZE, Integer.valueOf(1));
+ return maxStackSize; // Leaf - Cache ItemStack max stack size
}

+ // Leaf start - Cache ItemStack max stack size
+ private int getMaxStackSizeInternal() {
+ return this.getOrDefault(DataComponents.MAX_STACK_SIZE, 1);
+ }
+ // Leaf end - Cache ItemStack max stack size
+
public boolean isStackable() {
return this.getMaxStackSize() > 1 && (!this.isDamageableItem() || !this.isDamaged());
}
@@ -1339,6 +1348,7 @@ public final class ItemStack implements DataComponentHolder, net.caffeinemc.mods
this.components = new PatchedDataComponentMap(this.item.components());
this.applyComponents(patch);
// Paper end - change base component prototype
+ this.maxStackSize = getMaxStackSizeInternal(); // Leaf - Cache ItemStack max stack size
}
// CraftBukkit end

@@ -1396,6 +1406,7 @@ public final class ItemStack implements DataComponentHolder, net.caffeinemc.mods
}
// Leaf end - Lithium - equipment tracking
this.count = count;
+ maxStackSize = count <= 0 ? 1 : getMaxStackSizeInternal(); // Leaf - Cache ItemStack max stack size - taken from ItemStack#isEmpty
}

public void limitSize(int maxSize) {
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on entity count, if entity count doesn't reach the Bucket Sort threshold,
FastBitRadix Sort will be used. (see https://ieeexplore.ieee.org/document/7822019 for more)
When entity count reached the threshold, Bucket Sort will be used.

In non-strict testing, this can give ~20-40% improvement (54MSPT -> 44MSPT),
In non-strict test, this can give ~20-40% improvement (54MSPT -> 44MSPT),
under 625 villagers situation.

diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrPowerGamerBR <[email protected]>
Date: Sun, 26 Nov 2023 13:02:16 -0300
Subject: [PATCH] PaperPR: Fix MC-117075: Block Entities Unload Lag Spike

Original license: GPLv3
Original project: https://github.com/SparklyPower/SparklyPaper
Paper pull request: https://github.com/PaperMC/Paper/pull/9970

We replaced the `blockEntityTickers` list with a custom list based on fastutil's `ObjectArrayList` with a small yet huge change for us: A method that allows us to remove a list of indexes from the list.

This is WAY FASTER than using `removeAll` with a list of entries to be removed, because we don't need to calculate the identity of each block entity to be removed, and we can jump directly to where the search should begin, giving a performance boost for small removals (because we don't need to loop thru the entire list to find what element should be removed) and a performance boost for big removals (no need to calculate the identity of each block entity).

diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 53cabe7dabc83618c8941c95e95c5b7e23ee694e..7d3163802640449b6bdaa93595518d7d0f62488b 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -113,7 +113,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
public static final int TICKS_PER_DAY = 24000;
public static final int MAX_ENTITY_SPAWN_Y = 20000000;
public static final int MIN_ENTITY_SPAWN_Y = -20000000;
- public final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList(); // Paper - public
+ public final org.dreeam.leaf.util.list.BlockEntityTickersList blockEntityTickers = new org.dreeam.leaf.util.list.BlockEntityTickersList(); // Paper - public // SparklyPaper - optimize block entity removals
protected final NeighborUpdater neighborUpdater;
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
private boolean tickingBlockEntities;
@@ -1523,14 +1523,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
boolean runsNormally = this.tickRateManager().runsNormally();

int tickedEntities = 0; // Paper - rewrite chunk system
- var toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<TickingBlockEntity>(); // Paper - Fix MC-117075; use removeAll
- toRemove.add(null); // Paper - Fix MC-117075
for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters
this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0;
TickingBlockEntity tickingBlockEntity = this.blockEntityTickers.get(this.tileTickPosition);
// Spigot end
if (tickingBlockEntity.isRemoved()) {
- toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll
+ this.blockEntityTickers.markAsRemoved(this.tileTickPosition); // toRemove.add(tickingBlockEntity); // SparklyPaper - optimize block entity removals // Paper - Fix MC-117075; use removeAll
} else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) {
tickingBlockEntity.tick();
// Paper start - rewrite chunk system
@@ -1540,7 +1538,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
// Paper end - rewrite chunk system
}
}
- this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
+ this.blockEntityTickers.removeMarkedEntries(); // SparklyPaper - optimize block entity removals

this.tickingBlockEntities = false;
this.spigotConfig.currentPrimedTnt = 0; // Spigot
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: cao-awa <[email protected]>
Date: Fri, 23 Aug 2024 00:23:32 +0800
Subject: [PATCH] Sepals: Rearrange the attackable conditions

Original license: GPLv3
Original project: https://github.com/cao-awa/Sepals

Rearrange the attackable conditions
let less costs predicate running first
reduce the probability of high-costs calculating

-- The complaints --
Mojang's attackable predicate is:

!entity.getBrain().hasMemoryModule(MemoryModuleType.HAS_HUNTING_COOLDOWN)
&& Sensor.testAttackableTargetPredicate(entity, target)
&& FrogEntity.isValidFrogFood(target)
&& !this.isTargetUnreachable(entity, target)
&& target.isInRange(entity, 10.0)

in this case, 'Sensor#testAttackableTargetPredicate' has calls 'TargetPredicate#test'
that cause a very lots raycast calculate when entities too much in the area
but... minecraft's raycast is absolutely bad, very slow

the 'TargetPredicate#test' in this case (800 frogs) has make 9.8ms costs in once game tick
among them, 'BlockView.raycast' contributed 7.3ms

then i make it be:

FrogEntity.isValidFrogFood(target) &&
entity.getBrain().hasMemoryModule(MemoryModuleType.HAS_HUNTING_COOLDOWN) &&
target.isInRange(entity, 10.0) &&
Sensor.testAttackableTargetPredicate(entity, target) &&
isTargetUnreachable(entity, target);

the 'isValidFrogFood' is simple conditions, check the entity's tag has in 'frog_food'
and a extra check when entity is slime then skip it when it size not 1

the 'isInRange' and 'hasMemoryModule' also simple, it only a few math calculates

Test Result:
800 frogs cramming in a 7x7 space:

| Environment | time | Percent(Avg.) |
|-------------------------------------------------:|:------:|:-------------:|
| Vanilla (FrogAttackablesSensor#matches) | 10 ms | 100 % |
| With Lithium (FrogAttackablesSensor#matches) | 5.7 ms | 57 % |
| With Sepals (SepalsFrogBrain#attackable) | 0.1 ms | 1 % |
| With Sepals+Lithium (SepalsFrogBrain#attackable) | 0.1 ms | 1 % |

diff --git a/net/minecraft/world/entity/ai/sensing/FrogAttackablesSensor.java b/net/minecraft/world/entity/ai/sensing/FrogAttackablesSensor.java
index d163a363273b52b3b3f0b5a74ac4d4ab37d24bb7..e88479ba1ebeff67a93baad4f6f8c83119ff5ff7 100644
--- a/net/minecraft/world/entity/ai/sensing/FrogAttackablesSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/FrogAttackablesSensor.java
@@ -13,11 +13,11 @@ public class FrogAttackablesSensor extends NearestVisibleLivingEntitySensor {

@Override
protected boolean isMatchingEntity(ServerLevel level, LivingEntity entity, LivingEntity target) {
- return !entity.getBrain().hasMemoryValue(MemoryModuleType.HAS_HUNTING_COOLDOWN)
+ return Frog.canEat(target)
+ && !entity.getBrain().hasMemoryValue(MemoryModuleType.HAS_HUNTING_COOLDOWN)
+ && target.closerThan(entity, 10.0)
&& Sensor.isEntityAttackable(level, entity, target)
- && Frog.canEat(target)
- && !this.isUnreachableAttackTarget(entity, target)
- && target.closerThan(entity, 10.0);
+ && !this.isUnreachableAttackTarget(entity, target); // Sepals - Rearrange the attackable conditions
}

private boolean isUnreachableAttackTarget(LivingEntity attacker, LivingEntity target) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrPowerGamerBR <[email protected]>
Date: Mon, 13 Jan 2025 14:32:08 -0300
Subject: [PATCH] SparklyPaper: Skip dirty stats copy when requesting player
stats


diff --git a/net/minecraft/stats/ServerStatsCounter.java b/net/minecraft/stats/ServerStatsCounter.java
index b26dbe807e5cb0a42f6c06b933397902310e5616..ce89060bd01b253af7577fd0e6c03fc95f046b91 100644
--- a/net/minecraft/stats/ServerStatsCounter.java
+++ b/net/minecraft/stats/ServerStatsCounter.java
@@ -81,11 +81,15 @@ public class ServerStatsCounter extends StatsCounter {
this.dirty.add(stat);
}

+ // SparklyPaper start - Skip dirty stats copy when requesting player stats
+ /*
private Set<Stat<?>> getDirty() {
Set<Stat<?>> set = Sets.newHashSet(this.dirty);
this.dirty.clear();
return set;
}
+ */
+ // SparklyPaper end

public void parseLocal(DataFixer fixerUpper, String json) {
try {
@@ -194,10 +198,12 @@ public class ServerStatsCounter extends StatsCounter {
public void sendStats(ServerPlayer player) {
Object2IntMap<Stat<?>> map = new Object2IntOpenHashMap<>();

- for (Stat<?> stat : this.getDirty()) {
+ for (Stat<?> stat : this.dirty) { // SparklyPaper - Skip dirty stats copy when requesting player stats
map.put(stat, this.getValue(stat));
}

+ this.dirty.clear(); // SparklyPaper - Skip dirty stats copy when requesting player stats
+
player.connection.send(new ClientboundAwardStatsPacket(map));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrPowerGamerBR <[email protected]>
Date: Wed, 5 Jun 2024 15:20:00 -0300
Subject: [PATCH] SparklyPaper: Reset dirty flag when loading maps from the
disk

By default, the server will start rewriting all map datas to the disk after loading it, even if the map didn't have any changes

This also slows down world saving a lot if you have a lot of maps

diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
index 681dec447486138088fe5f705ef4fadab531139f..07f9287ff1f1dbd1795582c74102c072ea59b29f 100644
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -198,6 +198,7 @@ public class MapItemSavedData extends SavedData {
}
}

+ mapItemSavedData.setDirty(false); // SparklyPaper - reset dirty flag when loading maps from the disk (context for updates: this modification is at the end of the map "load" function)
return mapItemSavedData;
}

Loading