mirror of
https://github.com/YatopiaMC/Yatopia.git
synced 2024-08-22 05:42:48 +02:00
Dropped hopper optimizations patch by tr7zw. Sorry buddy, but the patch was making more problems than it was solving. By no means this is an unneded patch, we will reimplement it in the future the way it should've been implemented. Fixes #148
314 lines
16 KiB
Diff
314 lines
16 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Aikar <aikar@aikar.co>
|
|
Date: Mon, 10 Aug 2020 17:12:02 +0300
|
|
Subject: [PATCH] Optimize Villagers
|
|
|
|
This change reimplements the entire BehaviorFindPosition method to
|
|
get rid of all of the streams, and implement the logic in a more sane way.
|
|
|
|
We keep vanilla behavior 100% the same with this change, just wrote more
|
|
optimal, as we can abort iterating POI's as soon as we find a match...
|
|
|
|
One slight change is that Minecraft adds a random delay before a POI is
|
|
attempted again. I've increased the amount of that delay based on the distance
|
|
to said POI, so farther POI's will not be attempted as often.
|
|
|
|
Additionally, we spiral out, so we favor local POI's before we ever favor farther POI's.
|
|
|
|
We also try to pathfind 1 POI at a time instead of collecting multiple POI's then tossing them
|
|
all to the pathfinder, so that once we get a match we can return before even looking at other
|
|
POI's.
|
|
|
|
This benefits us in that ideally, a villager will constantly find the near POI's and
|
|
not even try to pathfind to the farther POI. Trying to pathfind to distant POI's is
|
|
what causes significant lag.
|
|
|
|
Other improvements here is to stop spamming the POI manager with empty nullables.
|
|
Vanilla used them to represent if they needed to load POI data off disk or not.
|
|
|
|
Well, we load POI data async on chunk load, so we have it, and we surely do not ever
|
|
want to load POI data sync either for unloaded chunks!
|
|
|
|
So this massively reduces object count in the POI hashmaps, resulting in less hash collions,
|
|
and also less memory use.
|
|
|
|
Additionally, unemployed villagers were using significant time due to major inefficiency in
|
|
the code rebuilding data that is static every single invocation of every POI type...
|
|
|
|
So we cache that and only rebuild it if professions change, which should be never unless
|
|
a plugin manipulates and adds custom professions, which it will handle by rebuilding.
|
|
|
|
Ported to Yatopia and 1.16.1 by MrIvanPlays
|
|
Co-authored-by: MrIvanPlays <ivan@mrivanplays.com>
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/BehaviorFindPosition.java b/src/main/java/net/minecraft/server/BehaviorFindPosition.java
|
|
index 63a761ebef80d4af09cdc2682e496d78492c4a3a..42ef6fd1c5a61f84b50ce9993d0c42152466a089 100644
|
|
--- a/src/main/java/net/minecraft/server/BehaviorFindPosition.java
|
|
+++ b/src/main/java/net/minecraft/server/BehaviorFindPosition.java
|
|
@@ -48,7 +48,7 @@ public class BehaviorFindPosition extends Behavior<EntityCreature> {
|
|
if (this.d && entitycreature.isBaby()) {
|
|
return false;
|
|
} else if (this.f == 0L) {
|
|
- this.f = entitycreature.world.getTime() + (long) worldserver.random.nextInt(20);
|
|
+ this.f = entitycreature.world.getTime() + (long) java.util.concurrent.ThreadLocalRandom.current().nextInt(20); // Yatopia
|
|
return false;
|
|
} else {
|
|
return worldserver.getTime() >= this.f;
|
|
@@ -56,12 +56,57 @@ public class BehaviorFindPosition extends Behavior<EntityCreature> {
|
|
}
|
|
|
|
protected void a(WorldServer worldserver, EntityCreature entitycreature, long i) {
|
|
- this.f = i + 20L + (long) worldserver.getRandom().nextInt(20);
|
|
+ this.f = i + 20L + (long) java.util.concurrent.ThreadLocalRandom.current().nextInt(20); // Yatopia
|
|
VillagePlace villageplace = worldserver.y();
|
|
|
|
+ // Yatopia start - replace implementation completely
|
|
+ BlockPosition blockposition2 = new BlockPosition(entitycreature.locX(), entitycreature.locY(), entitycreature.locZ());
|
|
+ int dist = 48;
|
|
+ int requiredDist = dist * dist;
|
|
+ int cdist = Math.floorDiv(dist, 16);
|
|
+ Predicate<VillagePlaceType> predicate = this.b.getPredicate();
|
|
+ int maxPoiAttempts = 4;
|
|
+ int poiAttempts = 0;
|
|
+ OUT:
|
|
+ for (ChunkCoordIntPair chunkcoordintpair : MCUtil.getSpiralOutChunks(blockposition2, cdist)) {
|
|
+ for (int i1 = 0; i1 < 16; i1++) {
|
|
+ java.util.Optional<VillagePlaceSection> section = villageplace.getSection(SectionPosition.a(chunkcoordintpair, i1).asLong());
|
|
+ if (section == null || !section.isPresent()) continue;
|
|
+ for (java.util.Map.Entry<VillagePlaceType, java.util.Set<VillagePlaceRecord>> e : section.get().getRecords().entrySet()) {
|
|
+ if (!predicate.test(e.getKey())) continue;
|
|
+ for (VillagePlaceRecord record : e.getValue()) {
|
|
+ if (!record.hasVacancy()) continue;
|
|
+
|
|
+ BlockPosition pos = record.getPosition();
|
|
+ long key = pos.asLong();
|
|
+ if (this.g.containsKey(key)) {
|
|
+ continue;
|
|
+ }
|
|
+ double poiDist = pos.distanceSquared(blockposition2);
|
|
+ if (poiDist <= (double) requiredDist) {
|
|
+ this.g.put(key, new BehaviorFindPosition.a(java.util.concurrent.ThreadLocalRandom.current(), (long) (this.f + Math.sqrt(poiDist) * 4)))
|
|
+ ; // use dist instead of 40 to blacklist longer if farther distance
|
|
+ ++poiAttempts;
|
|
+ PathEntity pathentity = entitycreature.getNavigation().a(com.google.common.collect.ImmutableSet.of(pos), 8, false, this.b.getValidRange());
|
|
+
|
|
+ if (pathentity != null && pathentity.canReach()) {
|
|
+ GlobalPos globalPos = GlobalPos.create(worldserver.getDimensionKey(), pos);
|
|
+ entitycreature.getBehaviorController().setMemory(c, globalPos);
|
|
+ break OUT;
|
|
+ }
|
|
+ if (poiAttempts >= maxPoiAttempts) {
|
|
+ break OUT;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
this.g.long2ObjectEntrySet().removeIf((entry) -> {
|
|
return !((BehaviorFindPosition.a) entry.getValue()).b(i);
|
|
});
|
|
+ /*
|
|
Predicate<BlockPosition> predicate = (blockposition) -> {
|
|
BehaviorFindPosition.a behaviorfindposition_a = (BehaviorFindPosition.a) this.g.get(blockposition.asLong());
|
|
|
|
@@ -102,7 +147,7 @@ public class BehaviorFindPosition extends Behavior<EntityCreature> {
|
|
});
|
|
}
|
|
}
|
|
-
|
|
+ */ // Yatopia end
|
|
}
|
|
|
|
static class a {
|
|
diff --git a/src/main/java/net/minecraft/server/PathEntity.java b/src/main/java/net/minecraft/server/PathEntity.java
|
|
index c81a5d50c480b064ab60ed6f25f9e2c0bedb6ece..a86ad4c8a28b9aacdb1e99320fddf2344b08bd7e 100644
|
|
--- a/src/main/java/net/minecraft/server/PathEntity.java
|
|
+++ b/src/main/java/net/minecraft/server/PathEntity.java
|
|
@@ -114,6 +114,7 @@ public class PathEntity {
|
|
}
|
|
}
|
|
|
|
+ public final boolean canReach() { return j(); } // Yatopia - OBFHELPER
|
|
public boolean j() {
|
|
return this.h;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/RegionFileSection.java b/src/main/java/net/minecraft/server/RegionFileSection.java
|
|
index 04256a95108b8182e8f808e856e0d2b62165e242..69cc2d1a0642029793827f4195723c380e01c821 100644
|
|
--- a/src/main/java/net/minecraft/server/RegionFileSection.java
|
|
+++ b/src/main/java/net/minecraft/server/RegionFileSection.java
|
|
@@ -52,10 +52,13 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
|
|
|
|
@Nullable
|
|
protected Optional<R> c(long i) {
|
|
- return (Optional) this.c.get(i);
|
|
+ return this.c.getOrDefault(i, Optional.empty()); // Yatopia
|
|
}
|
|
|
|
+ protected final Optional<R> getSection(long i) { return d(i); } // Yatopia - OBFHELPER
|
|
protected Optional<R> d(long i) {
|
|
+ // Yatopia start - replace method - never load POI data sync, we load this in chunk load already, reduce ops
|
|
+ /*
|
|
SectionPosition sectionposition = SectionPosition.a(i);
|
|
|
|
if (this.b(sectionposition)) {
|
|
@@ -75,6 +78,10 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
|
|
}
|
|
}
|
|
}
|
|
+ */
|
|
+ // If it's an unloaded chunk, well too bad.
|
|
+ return this.c(i);
|
|
+ // Yatopia end
|
|
}
|
|
|
|
protected boolean b(SectionPosition sectionposition) {
|
|
@@ -118,7 +125,7 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
|
|
private <T> void a(ChunkCoordIntPair chunkcoordintpair, DynamicOps<T> dynamicops, @Nullable T t0) {
|
|
if (t0 == null) {
|
|
for (int i = 0; i < 16; ++i) {
|
|
- this.c.put(SectionPosition.a(chunkcoordintpair, i).s(), Optional.empty());
|
|
+ //this.c.put(SectionPosition.a(chunkcoordintpair, i).s(), Optional.empty()); // Yatopia - NO!!!
|
|
}
|
|
} else {
|
|
Dynamic<T> dynamic = new Dynamic(dynamicops, t0);
|
|
@@ -140,7 +147,7 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
|
|
return dataresult.resultOrPartial(logger::error);
|
|
});
|
|
|
|
- this.c.put(i1, optional);
|
|
+ if (optional.isPresent()) this.c.put(i1, optional); // Yatopia
|
|
optional.ifPresent((object) -> {
|
|
this.b(i1);
|
|
if (flag) {
|
|
@@ -213,7 +220,7 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
|
|
if (optional != null && optional.isPresent()) {
|
|
this.d.add(i);
|
|
} else {
|
|
- RegionFileSection.LOGGER.warn("No data for position: {}", SectionPosition.a(i));
|
|
+ //RegionFileSection.LOGGER.warn("No data for position: {}", SectionPosition.a(i)); // Yatopia - hush
|
|
}
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/SectionPosition.java b/src/main/java/net/minecraft/server/SectionPosition.java
|
|
index f95925f1c5d091f1a129d0437bb6e175c6ac080f..cf5b25d9375724ea2afcf5cd59e0ccd302cdf45e 100644
|
|
--- a/src/main/java/net/minecraft/server/SectionPosition.java
|
|
+++ b/src/main/java/net/minecraft/server/SectionPosition.java
|
|
@@ -173,6 +173,7 @@ public class SectionPosition extends BaseBlockPosition {
|
|
return (((long) i & 4194303L) << 42) | (((long) j & 1048575L)) | (((long) k & 4194303L) << 20); // Paper - Simplify to reduce instruction count
|
|
}
|
|
|
|
+ public 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
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/VillagePlaceRecord.java b/src/main/java/net/minecraft/server/VillagePlaceRecord.java
|
|
index 0b40c2f4dada7d8432e3f91e9cf206c2bda3b24b..1b956d973ebef2345755201dec3449545c458a60 100644
|
|
--- a/src/main/java/net/minecraft/server/VillagePlaceRecord.java
|
|
+++ b/src/main/java/net/minecraft/server/VillagePlaceRecord.java
|
|
@@ -44,6 +44,7 @@ public class VillagePlaceRecord {
|
|
}
|
|
}
|
|
|
|
+ protected final boolean increaseVacancy() { return c(); } // Yatopia - OBFHELPER
|
|
protected boolean c() {
|
|
if (this.c >= this.b.b()) {
|
|
return false;
|
|
@@ -54,14 +55,17 @@ public class VillagePlaceRecord {
|
|
}
|
|
}
|
|
|
|
+ public final boolean hasVacancy() { return d(); } // Yatopia - OBFHELPER
|
|
public boolean d() {
|
|
return this.c > 0;
|
|
}
|
|
|
|
+ public final boolean isOccupied() { return e(); } // Yatopia - OBFHELPER
|
|
public boolean e() {
|
|
return this.c != this.b.b();
|
|
}
|
|
|
|
+ public final BlockPosition getPosition() { return f(); } // Yatopia - OBFHELPER
|
|
public BlockPosition f() {
|
|
return this.a;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/VillagePlaceSection.java b/src/main/java/net/minecraft/server/VillagePlaceSection.java
|
|
index 77c66bc9952542d2444b402896a3d9f622ca2ff9..d4018b9b615dae2b9e30517be51322656601b171 100644
|
|
--- a/src/main/java/net/minecraft/server/VillagePlaceSection.java
|
|
+++ b/src/main/java/net/minecraft/server/VillagePlaceSection.java
|
|
@@ -23,12 +23,12 @@ public class VillagePlaceSection {
|
|
|
|
private static final Logger LOGGER = LogManager.getLogger();
|
|
private final Short2ObjectMap<VillagePlaceRecord> b;
|
|
- private final Map<VillagePlaceType, Set<VillagePlaceRecord>> c;
|
|
+ private final Map<VillagePlaceType, Set<VillagePlaceRecord>> c; public final Map<VillagePlaceType, Set<VillagePlaceRecord>> getRecords() { return c; } // Yatopia - OBFHELPER
|
|
private final Runnable d;
|
|
private boolean e;
|
|
|
|
public static Codec<VillagePlaceSection> a(Runnable runnable) {
|
|
- Codec codec = RecordCodecBuilder.create((instance) -> {
|
|
+ Codec<VillagePlaceSection> 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) -> {
|
|
diff --git a/src/main/java/net/minecraft/server/VillagePlaceType.java b/src/main/java/net/minecraft/server/VillagePlaceType.java
|
|
index a5718af9b614ae505067131f04ebb490617d6aa4..142b47df08991a3e72c9f7927af6933a72f7b4cb 100644
|
|
--- a/src/main/java/net/minecraft/server/VillagePlaceType.java
|
|
+++ b/src/main/java/net/minecraft/server/VillagePlaceType.java
|
|
@@ -14,11 +14,20 @@ import java.util.stream.Collectors;
|
|
|
|
public class VillagePlaceType {
|
|
|
|
+ static Set<VillagePlaceType> professionCache; // Yatopia
|
|
private static final Supplier<Set<VillagePlaceType>> y = Suppliers.memoize(() -> {
|
|
return (Set) IRegistry.VILLAGER_PROFESSION.g().map(VillagerProfession::b).collect(Collectors.toSet());
|
|
});
|
|
public static final Predicate<VillagePlaceType> a = (villageplacetype) -> {
|
|
- return ((Set) VillagePlaceType.y.get()).contains(villageplacetype);
|
|
+ // Yatopia start
|
|
+ if (professionCache == null) {
|
|
+ professionCache = new java.util.HashSet<>();
|
|
+ for (VillagerProfession profession : IRegistry.VILLAGER_PROFESSION) {
|
|
+ professionCache.add(profession.getPlaceType());
|
|
+ }
|
|
+ }
|
|
+ return professionCache.contains(villageplacetype);
|
|
+ // Yatopia end
|
|
};
|
|
public static final Predicate<VillagePlaceType> b = (villageplacetype) -> {
|
|
return true;
|
|
@@ -83,10 +92,12 @@ public class VillagePlaceType {
|
|
return this.D;
|
|
}
|
|
|
|
+ public final Predicate<VillagePlaceType> getPredicate() { return c(); } // Yatopia - OBFHELPER
|
|
public Predicate<VillagePlaceType> c() {
|
|
return this.E;
|
|
}
|
|
|
|
+ public final int getValidRange() { return d(); } // Yatopia - OBFHELPER
|
|
public int d() {
|
|
return this.F;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/VillagerProfession.java b/src/main/java/net/minecraft/server/VillagerProfession.java
|
|
index 3c60da7ac6faebe9d964e893974e42613c59b4c1..1b012914cb3fcbc4bb456195ade96668b6742cfd 100644
|
|
--- a/src/main/java/net/minecraft/server/VillagerProfession.java
|
|
+++ b/src/main/java/net/minecraft/server/VillagerProfession.java
|
|
@@ -35,6 +35,7 @@ public class VillagerProfession {
|
|
this.t = soundeffect;
|
|
}
|
|
|
|
+ public final VillagePlaceType getPlaceType() { return b(); } // Yatopia - OBFHELPER
|
|
public VillagePlaceType b() {
|
|
return this.q;
|
|
}
|
|
@@ -61,6 +62,7 @@ public class VillagerProfession {
|
|
}
|
|
|
|
static VillagerProfession a(String s, VillagePlaceType villageplacetype, ImmutableSet<Item> immutableset, ImmutableSet<Block> immutableset1, @Nullable SoundEffect soundeffect) {
|
|
+ VillagePlaceType.professionCache = null; // Yatopia
|
|
return (VillagerProfession) IRegistry.a((IRegistry) IRegistry.VILLAGER_PROFESSION, new MinecraftKey(s), (Object) (new VillagerProfession(s, villageplacetype, immutableset, immutableset1, soundeffect)));
|
|
}
|
|
}
|