aboutsummaryrefslogtreecommitdiffhomepage
path: root/paper-server/patches/features/0014-Remove-streams-from-hot-code.patch
blob: afbe9f1e4c87b6ffd307611ebaada793acd550bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Josh Roy <10731363+JRoy@users.noreply.github.com>
Date: Wed, 1 Jul 2020 18:01:49 -0400
Subject: [PATCH] Remove streams from hot code

Co-authored-by: Bjarne Koll <git@lynxplay.dev>
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>

diff --git a/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/net/minecraft/world/entity/ai/behavior/GateBehavior.java
index c215d97c24e6501e1a48a76fc08bf48ff4dfe462..bd31d1cac0d022a72bd536c41d1ef811886e7068 100644
--- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java
+++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java
@@ -57,7 +57,7 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
         if (this.hasRequiredMemories(entity)) {
             this.status = Behavior.Status.RUNNING;
             this.orderPolicy.apply(this.behaviors);
-            this.runningPolicy.apply(this.behaviors.stream(), level, entity, gameTime);
+            this.runningPolicy.apply(this.behaviors, level, entity, gameTime); // Paper - Perf: Remove streams from hot code
             return true;
         } else {
             return false;
@@ -66,10 +66,13 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
 
     @Override
     public final void tickOrStop(ServerLevel level, E entity, long gameTime) {
-        this.behaviors
-            .stream()
-            .filter(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)
-            .forEach(behavior -> behavior.tickOrStop(level, entity, gameTime));
+        // Paper start - Perf: Remove streams from hot code
+        for (final BehaviorControl<? super E> behavior : this.behaviors) {
+            if (behavior.getStatus() == Behavior.Status.RUNNING) {
+                behavior.tickOrStop(level, entity, gameTime);
+            }
+        }
+        // Paper end - Perf: Remove streams from hot code
         if (this.behaviors.stream().noneMatch(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)) {
             this.doStop(level, entity, gameTime);
         }
@@ -78,11 +81,16 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
     @Override
     public final void doStop(ServerLevel level, E entity, long gameTime) {
         this.status = Behavior.Status.STOPPED;
-        this.behaviors
-            .stream()
-            .filter(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)
-            .forEach(behavior -> behavior.doStop(level, entity, gameTime));
-        this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory);
+        // Paper start - Perf: Remove streams from hot code
+        for (final BehaviorControl<? super E> behavior : this.behaviors) {
+            if (behavior.getStatus() == Behavior.Status.RUNNING) {
+                behavior.doStop(level, entity, gameTime);
+            }
+        }
+        for (final MemoryModuleType<?> exitErasedMemory : this.exitErasedMemories) {
+            entity.getBrain().eraseMemory(exitErasedMemory);
+        }
+        // Paper end - Perf: Remove streams from hot code
     }
 
     @Override
@@ -116,20 +124,30 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
 
     public static enum RunningPolicy {
         RUN_ONE {
+            // Paper start - Perf: Remove streams from hot code
             @Override
-            public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
-                behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED)
-                    .filter(behavior -> behavior.tryStart(level, owner, gameTime))
-                    .findFirst();
+            public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
+                for (final BehaviorControl<? super E> behavior : behaviors) {
+                    if (behavior.getStatus() == Behavior.Status.STOPPED && behavior.tryStart(level, owner, gameTime)) {
+                        break;
+                    }
+                }
+                // Paper end - Perf: Remove streams from hot code
             }
         },
         TRY_ALL {
+            // Paper start - Perf: Remove streams from hot code
             @Override
-            public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
-                behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED).forEach(behavior -> behavior.tryStart(level, owner, gameTime));
+            public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
+                for (final BehaviorControl<? super E> behavior : behaviors) {
+                    if (behavior.getStatus() == Behavior.Status.STOPPED) {
+                        behavior.tryStart(level, owner, gameTime);
+                    }
+                }
+                // Paper end - Perf: Remove streams from hot code
             }
         };
 
-        public abstract <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime);
+        public abstract <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime); // Paper - Perf: Remove streams from hot code
     }
 }
diff --git a/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/net/minecraft/world/entity/ai/gossip/GossipContainer.java
index 2c839dc80f451c83135828a97aced1a531004bab..b74a4ce1b629d440681a1f5c026997ccaf1d0373 100644
--- a/net/minecraft/world/entity/ai/gossip/GossipContainer.java
+++ b/net/minecraft/world/entity/ai/gossip/GossipContainer.java
@@ -59,8 +59,22 @@ public class GossipContainer {
         return this.gossips.entrySet().stream().flatMap(gossip -> gossip.getValue().unpack(gossip.getKey()));
     }
 
+    // Paper start - Perf: Remove streams from hot code
+    private List<GossipContainer.GossipEntry> decompress() {
+        List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+        for (Map.Entry<UUID, GossipContainer.EntityGossips> entry : this.gossips.entrySet()) {
+            for (GossipContainer.GossipEntry cur : entry.getValue().decompress(entry.getKey())) {
+                if (cur.weightedValue() != 0) {
+                    list.add(cur);
+                }
+            }
+        }
+        return list;
+    }
+    // Paper end - Perf: Remove streams from hot code
+
     private Collection<GossipContainer.GossipEntry> selectGossipsForTransfer(RandomSource random, int amount) {
-        List<GossipContainer.GossipEntry> list = this.unpack().toList();
+        List<GossipContainer.GossipEntry> list = this.decompress(); // Paper - Perf: Remove streams from hot code
         if (list.isEmpty()) {
             return Collections.emptyList();
         } else {
@@ -145,7 +159,7 @@ public class GossipContainer {
 
     public <T> T store(DynamicOps<T> ops) {
         return GossipContainer.GossipEntry.LIST_CODEC
-            .encodeStart(ops, this.unpack().toList())
+            .encodeStart(ops, this.decompress()) // Paper - Perf: Remove streams from hot code
             .resultOrPartial(errorMessage -> LOGGER.warn("Failed to serialize gossips: {}", errorMessage))
             .orElseGet(ops::emptyList);
     }
@@ -172,12 +186,23 @@ public class GossipContainer {
         final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
 
         public int weightedValue(Predicate<GossipType> gossipType) {
-            return this.entries
-                .object2IntEntrySet()
-                .stream()
-                .filter(gossip -> gossipType.test(gossip.getKey()))
-                .mapToInt(gossip -> gossip.getIntValue() * gossip.getKey().weight)
-                .sum();
+            // Paper start - Perf: Remove streams from hot code
+            int weight = 0;
+            for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
+                if (gossipType.test(entry.getKey())) {
+                    weight += entry.getIntValue() * entry.getKey().weight;
+                }
+            }
+            return weight;
+        }
+
+        public List<GossipContainer.GossipEntry> decompress(UUID uuid) {
+            List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+            for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
+                list.add(new GossipContainer.GossipEntry(uuid, entry.getKey(), entry.getIntValue()));
+            }
+            return list;
+            // Paper end - Perf: Remove streams from hot code
         }
 
         public Stream<GossipContainer.GossipEntry> unpack(UUID identifier) {
diff --git a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
index 38873e56e95dc772b184e4271f7af1fb411ac9f8..09fd13e2d958da8326276c4dadf25bf488aff5ac 100644
--- a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
@@ -24,13 +24,17 @@ public class NearestItemSensor extends Sensor<Mob> {
     @Override
     protected void doTick(ServerLevel level, Mob entity) {
         Brain<?> brain = entity.getBrain();
-        List<ItemEntity> entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> true);
+        List<ItemEntity> entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(level, itemEntity.getItem())); // Paper - Perf: Move predicate into getEntities
         entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
-        Optional<ItemEntity> optional = entitiesOfClass.stream()
-            .filter(itemEntity -> entity.wantsToPickUp(level, itemEntity.getItem()))
-            .filter(itemEntity -> itemEntity.closerThan(entity, 32.0))
-            .filter(entity::hasLineOfSight)
-            .findFirst();
-        brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, optional);
+        // Paper start - Perf: remove streams from hot code
+        ItemEntity nearest = null;
+        for (final ItemEntity itemEntity : entitiesOfClass) {
+            if (entity.hasLineOfSight(itemEntity)) { // Paper - Perf: Move predicate into getEntities
+                nearest = itemEntity;
+                break;
+            }
+        }
+        brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, Optional.ofNullable(nearest));
+        // Paper end - Perf: remove streams from hot code
     }
 }
diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java
index 1a09da5aa1ae047a002d6779326c2a29e47d32b5..131923282c9ecbcb1d7f45a826da907c02bd2716 100644
--- a/net/minecraft/world/level/levelgen/Beardifier.java
+++ b/net/minecraft/world/level/levelgen/Beardifier.java
@@ -35,9 +35,10 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
         int minBlockZ = chunkPos.getMinBlockZ();
         ObjectList<Beardifier.Rigid> list = new ObjectArrayList<>(10);
         ObjectList<JigsawJunction> list1 = new ObjectArrayList<>(32);
-        structureManager.startsForStructure(chunkPos, structure -> structure.terrainAdaptation() != TerrainAdjustment.NONE)
-            .forEach(
-                structureStart -> {
+        // Paper start - Perf: Remove streams from hot code
+        for (net.minecraft.world.level.levelgen.structure.StructureStart structureStart : structureManager.startsForStructure(chunkPos, structure -> {
+            return structure.terrainAdaptation() != TerrainAdjustment.NONE;
+        })) { // Paper end - Perf: Remove streams from hot code
                     TerrainAdjustment terrainAdjustment = structureStart.getStructure().terrainAdaptation();
 
                     for (StructurePiece structurePiece : structureStart.getPieces()) {
@@ -65,8 +66,7 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
                             }
                         }
                     }
-                }
-            );
+        } // Paper - Perf: Remove streams from hot code
         return new Beardifier(list.iterator(), list1.iterator());
     }