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 Co-authored-by: Spottedleaf 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 implements BehaviorControl 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 implements BehaviorControl @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 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 implements BehaviorControl @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 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 implements BehaviorControl public static enum RunningPolicy { RUN_ONE { + // Paper start - Perf: Remove streams from hot code @Override - public void apply(Stream> behaviors, ServerLevel level, E owner, long gameTime) { - behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED) - .filter(behavior -> behavior.tryStart(level, owner, gameTime)) - .findFirst(); + public void apply(ShufflingList> behaviors, ServerLevel level, E owner, long gameTime) { + for (final BehaviorControl 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 void apply(Stream> behaviors, ServerLevel level, E owner, long gameTime) { - behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED).forEach(behavior -> behavior.tryStart(level, owner, gameTime)); + public void apply(ShufflingList> behaviors, ServerLevel level, E owner, long gameTime) { + for (final BehaviorControl behavior : behaviors) { + if (behavior.getStatus() == Behavior.Status.STOPPED) { + behavior.tryStart(level, owner, gameTime); + } + } + // Paper end - Perf: Remove streams from hot code } }; - public abstract void apply(Stream> behaviors, ServerLevel level, E owner, long gameTime); + public abstract void apply(ShufflingList> 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 decompress() { + List list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); + for (Map.Entry 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 selectGossipsForTransfer(RandomSource random, int amount) { - List list = this.unpack().toList(); + List 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 store(DynamicOps 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 entries = new Object2IntOpenHashMap<>(); public int weightedValue(Predicate 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 entry : entries.object2IntEntrySet()) { + if (gossipType.test(entry.getKey())) { + weight += entry.getIntValue() * entry.getKey().weight; + } + } + return weight; + } + + public List decompress(UUID uuid) { + List list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); + for (Object2IntMap.Entry 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 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 { @Override protected void doTick(ServerLevel level, Mob entity) { Brain brain = entity.getBrain(); - List entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> true); + List 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 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 list = new ObjectArrayList<>(10); ObjectList 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()); }