From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Ivan Pekov Date: Thu, 27 Aug 2020 10:46:17 +0300 Subject: [PATCH] Highly optimize VillagePlace filtering Replaced all streams I could. I expect this to be dropped in the next major release and reimplemented again if mojang changes stuff with villagers again. diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/Producer.java b/src/main/java/me/jellysquid/mods/lithium/common/util/Producer.java index f3224ea636fef95d368b934ed4b3e9060c4b10a2..f2d5878d235fdbfc11c74f87b95f029330c70309 100644 --- a/src/main/java/me/jellysquid/mods/lithium/common/util/Producer.java +++ b/src/main/java/me/jellysquid/mods/lithium/common/util/Producer.java @@ -46,6 +46,16 @@ public interface Producer { } } + // also checks contains and is thus only 1 generic + static void fillList(Producer producer, List list) { + HoldingConsumer consumer = new HoldingConsumer<>(); + while (producer.computeNext(consumer)) { + T value = consumer.getValue(); + if (value == null || list.contains(value)) { continue; } + list.add(value); + } + } + Producer EMPTY_PRODUCER = consumer -> false; @SuppressWarnings("unchecked") diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java index 6fcc7ed7c129e6a33386d65b37cbba4a44e96f0f..e6b5a21c523c598f53207d024322301fbae74825 100644 --- a/src/main/java/net/minecraft/server/BlockPosition.java +++ b/src/main/java/net/minecraft/server/BlockPosition.java @@ -341,6 +341,16 @@ public class BlockPosition extends BaseBlockPosition { return a(MathHelper.floor(axisalignedbb.minX), MathHelper.floor(axisalignedbb.minY), MathHelper.floor(axisalignedbb.minZ), MathHelper.floor(axisalignedbb.maxX), MathHelper.floor(axisalignedbb.maxY), MathHelper.floor(axisalignedbb.maxZ)); } + // Yatopia start + public static java.util.List getPositions(int i, int j, int k, int l, int i1, int j1) { + java.util.List ret = new java.util.ArrayList<>(); + Iterable iterable = b(i, j, k, l, i1, j1); + net.yatopia.server.HoldingConsumer consumer = new net.yatopia.server.HoldingConsumer<>(); + java.util.Spliterator spliterator = iterable.spliterator(); + while (spliterator.tryAdvance(consumer)) ret.add(consumer.getValue()); + return ret; + } + // Yatopia end public static Stream a(int i, int j, int k, int l, int i1, int j1) { return StreamSupport.stream(b(i, j, k, l, i1, j1).spliterator(), false); } diff --git a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java index dcaf9f8574a9c913b64ba3a1d8b02220db720225..3df4ae0f0921670c19abe17a115da428b4a1f534 100644 --- a/src/main/java/net/minecraft/server/ChunkCoordIntPair.java +++ b/src/main/java/net/minecraft/server/ChunkCoordIntPair.java @@ -116,6 +116,15 @@ public class ChunkCoordIntPair { return a(new ChunkCoordIntPair(chunkcoordintpair.x - i, chunkcoordintpair.z - i), new ChunkCoordIntPair(chunkcoordintpair.x + i, chunkcoordintpair.z + i)); } + // Yatopia start + public static java.util.List streamList(ChunkCoordIntPair center, int radius) { + return streamList(new ChunkCoordIntPair(center.x - radius, center.z - radius), new ChunkCoordIntPair(center.x + radius, center.z + radius)); + } + public static java.util.List streamList(ChunkCoordIntPair pos1, ChunkCoordIntPair pos2) { + return net.yatopia.server.YatopiaChunkPos.asList(pos1, pos2); + } + // Yatopia end + public static Stream a(final ChunkCoordIntPair chunkcoordintpair, final ChunkCoordIntPair chunkcoordintpair1) { int i = Math.abs(chunkcoordintpair.x - chunkcoordintpair1.x) + 1; int j = Math.abs(chunkcoordintpair.z - chunkcoordintpair1.z) + 1; diff --git a/src/main/java/net/minecraft/server/EntityBee.java b/src/main/java/net/minecraft/server/EntityBee.java index b1ff30fb1569ddf59f46240266ce32f0aa96da1a..68deb623508326841cf750fca45b53841d97d612 100644 --- a/src/main/java/net/minecraft/server/EntityBee.java +++ b/src/main/java/net/minecraft/server/EntityBee.java @@ -720,15 +720,24 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB private List j() { BlockPosition blockposition = EntityBee.this.getChunkCoordinates(); VillagePlace villageplace = ((WorldServer) EntityBee.this.world).y(); - Stream stream = villageplace.c((villageplacetype) -> { + List stream = villageplace.cList((villageplacetype) -> { // Yatopia return villageplacetype == VillagePlaceType.t || villageplacetype == VillagePlaceType.u; }, blockposition, 20, VillagePlace.Occupancy.ANY); - + // Yatopia start + List ret = new java.util.ArrayList<>(); + for (VillagePlaceRecord record : stream) { + BlockPosition pos = record.getPosition(); + if (i(pos)) { ret.add(pos); } + } + ret.sort(Comparator.comparingDouble((pos1) -> pos1.distanceSquared(blockposition))); + return ret; + /* return (List) stream.map(VillagePlaceRecord::f).filter((blockposition1) -> { return EntityBee.this.i(blockposition1); }).sorted(Comparator.comparingDouble((blockposition1) -> { return blockposition1.j(blockposition); })).collect(Collectors.toList()); + */ // Yatopia end } } diff --git a/src/main/java/net/minecraft/server/PersistentRaid.java b/src/main/java/net/minecraft/server/PersistentRaid.java index 2193fecab4406f49548c0952b2754269f91e2515..0785bfe1c28b63b492e25c678ebad89d4ed309eb 100644 --- a/src/main/java/net/minecraft/server/PersistentRaid.java +++ b/src/main/java/net/minecraft/server/PersistentRaid.java @@ -68,7 +68,7 @@ public class PersistentRaid extends PersistentBase { return null; } else { BlockPosition blockposition = entityplayer.getChunkCoordinates(); - List list = (List) this.b.y().c(VillagePlaceType.b, blockposition, 64, VillagePlace.Occupancy.IS_OCCUPIED).collect(Collectors.toList()); + List list = this.b.y().cList(VillagePlaceType.b, blockposition, 64, VillagePlace.Occupancy.IS_OCCUPIED); // Yatopia int i = 0; Vec3D vec3d = Vec3D.ORIGIN; diff --git a/src/main/java/net/minecraft/server/PortalTravelAgent.java b/src/main/java/net/minecraft/server/PortalTravelAgent.java index b4e1487489228b37af23f35033cf0892c7afce5f..bdb917595f863bdd2c2a0ad469101e5281337dcd 100644 --- a/src/main/java/net/minecraft/server/PortalTravelAgent.java +++ b/src/main/java/net/minecraft/server/PortalTravelAgent.java @@ -28,7 +28,7 @@ public class PortalTravelAgent { }).thenComparingInt((villageplacerecord) -> { return villageplacerecord.f().getY(); }); - java.util.List list = villageplace.b(type -> type == VillagePlaceType.v, blockposition, i, VillagePlace.Occupancy.ANY).collect(java.util.stream.Collectors.toList()); + java.util.List list = villageplace.bList(type -> type == VillagePlaceType.v, blockposition, i, VillagePlace.Occupancy.ANY); // Yatopia // Yatopia start - fix portal bug if (world.origamiConfig.useBlockDistanceInPortalSearchRadius) { list.removeIf(villagePlaceRecord -> { diff --git a/src/main/java/net/minecraft/server/SectionPosition.java b/src/main/java/net/minecraft/server/SectionPosition.java index f95925f1c5d091f1a129d0437bb6e175c6ac080f..6796b1a832779b65d337c63d6b600e2a3b5e9559 100644 --- a/src/main/java/net/minecraft/server/SectionPosition.java +++ b/src/main/java/net/minecraft/server/SectionPosition.java @@ -159,6 +159,7 @@ public class SectionPosition extends BaseBlockPosition { return this.p().b(8, 8, 8); } + public final ChunkCoordIntPair asChunkPos() { return r(); } // Yatopia - OBFHELPER public ChunkCoordIntPair r() { return new ChunkCoordIntPair(this.a(), this.c()); } @@ -173,10 +174,12 @@ public class SectionPosition extends BaseBlockPosition { return (((long) i & 4194303L) << 42) | (((long) j & 1048575L)) | (((long) k & 4194303L) << 20); // Paper - Simplify to reduce instruction count } + public final long asLong() { return s(); } // Yatopia - OBFHELPER public long s() { return (((long) getX() & 4194303L) << 42) | (((long) getY() & 1048575L)) | (((long) getZ() & 4194303L) << 20); // Paper - Simplify to reduce instruction count } + public java.util.List tList() { return BlockPosition.getPositions(d(), e(), f(), g(), h(), i()); } // Yatopia public Stream t() { return BlockPosition.a(this.d(), this.e(), this.f(), this.g(), this.h(), this.i()); } @@ -189,6 +192,18 @@ public class SectionPosition extends BaseBlockPosition { return a(chunkcoordintpair.x - i, 0, chunkcoordintpair.z - i, chunkcoordintpair.x + i, 15, chunkcoordintpair.z + i); // Paper - simplify/inline } + // Yatopia start + public static java.util.List getPosList(SectionPosition pos, int i) { + return getPosList(pos.getX() - i, pos.getY() - i, pos.getZ() - i, pos.getX() + i, pos.getY() + i, pos.getZ() + i); + } + public static java.util.List getPosList(ChunkCoordIntPair chunkPos, int i) { + return getPosList(chunkPos.x - i, 0, chunkPos.z - i, chunkPos.x + i, 15, chunkPos.z + i); + } + public static java.util.List getPosList(int i, int j, int k, int l, int i1, int j1) { + return net.yatopia.server.YatopiaChunkSectionPos.getChunkSectionPosList(i, j, k, l, i1, j1); + } + // Yatopia end + public static Stream a(final int i, final int j, final int k, final int l, final int i1, final int j1) { return StreamSupport.stream(new AbstractSpliterator((long) ((l - i + 1) * (i1 - j + 1) * (j1 - k + 1)), 64) { final CursorPosition a = new CursorPosition(i, j, k, l, i1, j1); diff --git a/src/main/java/net/minecraft/server/VillagePlace.java b/src/main/java/net/minecraft/server/VillagePlace.java index 6ab80cf7908437309a7346d71e42cf128a6f13d9..07a36d1955037524715181461cc2aa5d911b6efd 100644 --- a/src/main/java/net/minecraft/server/VillagePlace.java +++ b/src/main/java/net/minecraft/server/VillagePlace.java @@ -46,7 +46,7 @@ public class VillagePlace extends RegionFileSection { } public long a(Predicate predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { - return this.c(predicate, blockposition, i, villageplace_occupancy).count(); + return this.cList(predicate, blockposition, i, villageplace_occupancy).size(); // Yatopia } public boolean a(VillagePlaceType villageplacetype, BlockPosition blockposition) { @@ -67,6 +67,28 @@ public class VillagePlace extends RegionFileSection { }); } + // Yatopia start + public java.util.List bList(Predicate filter, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) { + int j = Math.floorDiv(i, 16) + 1; + + java.util.List list = ChunkCoordIntPair.streamList(new ChunkCoordIntPair(pos), j); + java.util.List ret = new java.util.ArrayList<>(); + for (ChunkCoordIntPair chunkPos : list) { + for (int k = 0; k < 16; k++) { // ITS THE LAW + this.d(SectionPosition.a(chunkPos, k).asLong()).ifPresent(section -> ret.addAll(section.aList(filter, occupancy))); + } + } + return ret; + } + public java.util.List cList(Predicate predicate, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) { + int j = i * i; + java.util.List ret = new java.util.ArrayList<>(); + for (VillagePlaceRecord record : this.bList(predicate, pos, i, occupancy)) { + if (record.getPosition().distanceSquared(pos) <= j) { ret.add(record); } + } + return ret; + } + public Stream c(Predicate predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { int j = i * i; @@ -83,10 +105,27 @@ public class VillagePlace extends RegionFileSection { }); } + // Yatopia start + public java.util.List aList(Predicate predicate, Predicate posFilter, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) { + java.util.List ret = new java.util.ArrayList<>(); + for (VillagePlaceRecord record : this.cList(predicate, pos, i, occupancy)) { + BlockPosition recordPosition = record.getPosition(); + if (posFilter.test(recordPosition)) ret.add(recordPosition); + } + return ret; + } + // Yatopia end public Stream a(Predicate predicate, Predicate predicate1, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { return this.c(predicate, blockposition, i, villageplace_occupancy).map(VillagePlaceRecord::f).filter(predicate1); } + // Yatopia start + public java.util.List bList(Predicate predicate, Predicate posFilter, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) { + java.util.List ret = aList(predicate, posFilter, pos, i, occupancy); + ret.sort(Comparator.comparingDouble((pos1) -> pos1.distanceSquared(pos))); + return ret; + } + // Yatopia ed public Stream b(Predicate predicate, Predicate predicate1, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { return this.a(predicate, predicate1, blockposition, i, villageplace_occupancy).sorted(Comparator.comparingDouble((blockposition1) -> { return blockposition1.j(blockposition); @@ -94,26 +133,53 @@ public class VillagePlace extends RegionFileSection { } public Optional c(Predicate predicate, Predicate predicate1, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { - return this.a(predicate, predicate1, blockposition, i, villageplace_occupancy).findFirst(); + // Yatopia start + java.util.List posList = aList(predicate, predicate1, blockposition, i, villageplace_occupancy); + return posList.isEmpty() ? Optional.empty() : Optional.of(posList.get(0)); + // Yatopia end } public Optional d(Predicate predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { + // Yatopia start + VillagePlaceRecord best = null; + for (VillagePlaceRecord record : cList(predicate, blockposition, i, villageplace_occupancy)) { + if (best == null || (record.getPosition().distanceSquared(blockposition) < best.getPosition().distanceSquared(blockposition))) { + best = record; + } + } + return best == null ? Optional.empty() : Optional.of(best.getPosition()); + /* return this.c(predicate, blockposition, i, villageplace_occupancy).map(VillagePlaceRecord::f).min(Comparator.comparingDouble((blockposition1) -> { return blockposition1.j(blockposition); })); + */ // Yatopia end } public Optional a(Predicate predicate, Predicate predicate1, BlockPosition blockposition, int i) { + // Yatopia start + java.util.List list = this.cList(predicate, blockposition, i, VillagePlace.Occupancy.HAS_SPACE); + java.util.List filtered = new java.util.ArrayList<>(); + for (VillagePlaceRecord record : list) { + if (predicate1.test(record.getPosition())) { + filtered.add(record); + } + } + if (filtered.isEmpty()) return Optional.empty(); + VillagePlaceRecord first = filtered.get(0); + first.b(); + return Optional.of(first.getPosition()); + /* return this.c(predicate, blockposition, i, VillagePlace.Occupancy.HAS_SPACE).filter((villageplacerecord) -> { return predicate1.test(villageplacerecord.f()); }).findFirst().map((villageplacerecord) -> { villageplacerecord.b(); return villageplacerecord.f(); }); + */ // Yatopia end } public Optional a(Predicate predicate, Predicate predicate1, VillagePlace.Occupancy villageplace_occupancy, BlockPosition blockposition, int i, Random random) { - List list = (List) this.c(predicate, blockposition, i, villageplace_occupancy).collect(Collectors.toList()); + List list = this.cList(predicate, blockposition, i, villageplace_occupancy); // Yatopia Collections.shuffle(list, random); for (VillagePlaceRecord villageplacerecord : list) { @@ -214,7 +280,7 @@ public class VillagePlace extends RegionFileSection { } private void a(ChunkSection chunksection, SectionPosition sectionposition, BiConsumer biconsumer) { - sectionposition.t().forEach((blockposition) -> { + sectionposition.tList().forEach((blockposition) -> { // Yatopia IBlockData iblockdata = chunksection.getType(SectionPosition.b(blockposition.getX()), SectionPosition.b(blockposition.getY()), SectionPosition.b(blockposition.getZ())); VillagePlaceType.b(iblockdata).ifPresent((villageplacetype) -> { @@ -224,6 +290,16 @@ public class VillagePlace extends RegionFileSection { } public void a(IWorldReader iworldreader, BlockPosition blockposition, int i) { + // Yatopia start - WHY? + java.util.List posList = SectionPosition.getPosList(new ChunkCoordIntPair(blockposition), Math.floorDiv(i, 16)); + for (SectionPosition pos : posList) { + boolean shouldContinue = this.d(pos.asLong()).map(VillagePlaceSection::a).orElse(false); + if (shouldContinue) { + ChunkCoordIntPair chunkPos = pos.asChunkPos(); + if (b.add(chunkPos.pair())) { iworldreader.getChunkAt(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY); } + } + } + /* SectionPosition.b(new ChunkCoordIntPair(blockposition), Math.floorDiv(i, 16)).map((sectionposition) -> { return Pair.of(sectionposition, this.d(sectionposition.s())); }).filter((pair) -> { @@ -235,6 +311,7 @@ public class VillagePlace extends RegionFileSection { }).forEach((chunkcoordintpair) -> { iworldreader.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z, ChunkStatus.EMPTY); }); + */ // Yatopia end } final class a extends LightEngineGraphSection { diff --git a/src/main/java/net/minecraft/server/VillagePlaceSection.java b/src/main/java/net/minecraft/server/VillagePlaceSection.java index 77c66bc9952542d2444b402896a3d9f622ca2ff9..b47abdabb592cfff6a4bf9ee638dd72f8a825499 100644 --- a/src/main/java/net/minecraft/server/VillagePlaceSection.java +++ b/src/main/java/net/minecraft/server/VillagePlaceSection.java @@ -28,7 +28,7 @@ public class VillagePlaceSection { private boolean e; public static Codec a(Runnable runnable) { - Codec codec = RecordCodecBuilder.create((instance) -> { + Codec codec = RecordCodecBuilder.create((instance) -> { // Yatopia - decompile fix return instance.group(RecordCodecBuilder.point(runnable), Codec.BOOL.optionalFieldOf("Valid", false).forGetter((villageplacesection) -> { return villageplacesection.e; }), VillagePlaceRecord.a(runnable).listOf().fieldOf("Records").forGetter((villageplacesection) -> { @@ -55,6 +55,17 @@ public class VillagePlaceSection { list.forEach(this::a); } + // Yatopia start + public java.util.List aList(Predicate predicate, VillagePlace.Occupancy occupancy) { + java.util.List ret = new java.util.ArrayList<>(); + for (Map.Entry> entry : c.entrySet()) { + if (predicate.test(entry.getKey())) { + for (VillagePlaceRecord record : entry.getValue()) { if (occupancy.a().test(record)) ret.add(record); } + } + } + return ret; + } + // Yatopia end public Stream a(Predicate predicate, VillagePlace.Occupancy villageplace_occupancy) { return this.c.entrySet().stream().filter((entry) -> { return predicate.test(entry.getKey()); diff --git a/src/main/java/net/yatopia/server/YatopiaChunkPos.java b/src/main/java/net/yatopia/server/YatopiaChunkPos.java new file mode 100644 index 0000000000000000000000000000000000000000..c7942b83b5c2d49e31c14eb51297baa365bb364f --- /dev/null +++ b/src/main/java/net/yatopia/server/YatopiaChunkPos.java @@ -0,0 +1,54 @@ +package net.yatopia.server; + +import java.util.LinkedList; +import java.util.List; +import java.util.function.Consumer; +import me.jellysquid.mods.lithium.common.util.Producer; +import net.minecraft.server.ChunkCoordIntPair; + +public class YatopiaChunkPos { + + public static List asList(ChunkCoordIntPair pos1, ChunkCoordIntPair pos2) { + List list = new LinkedList<>(); + Producer.fillList(getStreamProducer(pos1, pos2), list); + return list; + } + + /** + * [VanillaCopy] but in a producer + * + * @param pos1 pos 1 + * @param pos2 pos 2 + * @return producer + */ + private static Producer getStreamProducer(ChunkCoordIntPair pos1, ChunkCoordIntPair pos2) { + final int k = pos1.x < pos2.x ? 1 : -1; + final int l = pos1.z < pos2.z ? 1 : -1; + + return new Producer() { + private ChunkCoordIntPair pair = null; + + @Override + public boolean computeNext(Consumer consumer) { + if (pair == null) { + pair = pos1; + } else { + int i1 = this.pair.x; + int j1 = this.pair.z; + + if (i1 == pos2.x) { + if (j1 == pos2.z) { + return false; + } + + this.pair = new ChunkCoordIntPair(pos1.x, j1 + l); + } else { + this.pair = new ChunkCoordIntPair(i1 + k, j1); + } + } + consumer.accept(pair); + return true; + } + }; + } +} diff --git a/src/main/java/net/yatopia/server/YatopiaChunkSectionPos.java b/src/main/java/net/yatopia/server/YatopiaChunkSectionPos.java new file mode 100644 index 0000000000000000000000000000000000000000..d76e96eb055731338b670c6df2e3d9fcdc7e9a03 --- /dev/null +++ b/src/main/java/net/yatopia/server/YatopiaChunkSectionPos.java @@ -0,0 +1,32 @@ +package net.yatopia.server; + +import java.util.LinkedList; +import java.util.List; +import java.util.function.Consumer; +import me.jellysquid.mods.lithium.common.util.Producer; +import net.minecraft.server.CursorPosition; +import net.minecraft.server.SectionPosition; + +public class YatopiaChunkSectionPos { + + public static List getChunkSectionPosList(int i, int j, int k, int l, int i1, int j1) { + List list = new LinkedList<>(); + Producer.fillList(getChunkSectionPosProducer(i, j, k, l, i1, j1), list); + return list; + } + + private static Producer getChunkSectionPosProducer(int i, int j, int k, int l, int i1, int j1) { + return new Producer() { + final CursorPosition cursorPos = new CursorPosition(i, j, k, l, i1, j1); + + @Override + public boolean computeNext(Consumer consumer) { + if (cursorPos.a()) { + consumer.accept(SectionPosition.a(cursorPos.b(), cursorPos.c(), cursorPos.d())); + return true; + } + return false; + } + }; + } +}