mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-29 07:48:53 +01:00
port some patches (#5837)
This commit is contained in:
parent
8755b391fb
commit
b26ba5bc8a
8 changed files with 178 additions and 247 deletions
|
@ -1,99 +0,0 @@
|
||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Aikar <aikar@aikar.co>
|
|
||||||
Date: Wed, 12 Sep 2018 21:47:01 -0400
|
|
||||||
Subject: [PATCH] Optimize Biome Mob Lookups for Mob Spawning
|
|
||||||
|
|
||||||
Uses an EnumMap as well as a Set paired List for O(1) contains calls.
|
|
||||||
|
|
||||||
|
|
||||||
TODO 1.17: Does not look relevant now
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java
|
|
||||||
index 58ee27a994b4cd845b8bb28e80cc2102c860f097..528f42c63a1186b8827bfe7cf6193e14da938cb3 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java
|
|
||||||
@@ -30,19 +30,28 @@ public class MobSpawnSettings {
|
|
||||||
}, (enumcreaturetype) -> {
|
|
||||||
return ImmutableList.of();
|
|
||||||
})), ImmutableMap.of(), false);
|
|
||||||
+ // Paper start- decompile error workaround
|
|
||||||
+ private static class bProxy extends MobSpawnSettings.MobSpawnCost {
|
|
||||||
+ private bProxy(double gravityLimit, double mass) {
|
|
||||||
+ super(gravityLimit, mass);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ private static class cProxy extends MobSpawnSettings.SpawnerData {
|
|
||||||
+ public cProxy(EntityType<?> type, int weight, int minGroupSize, int maxGroupSize) {
|
|
||||||
+ super(type, weight, minGroupSize, maxGroupSize);
|
|
||||||
+ }
|
|
||||||
+ };
|
|
||||||
+ // Paper end
|
|
||||||
public static final MapCodec<MobSpawnSettings> CODEC = RecordCodecBuilder.mapCodec((instance) -> {
|
|
||||||
- RecordCodecBuilder recordcodecbuilder = Codec.FLOAT.optionalFieldOf("creature_spawn_probability", 0.1F).forGetter((biomesettingsmobs) -> {
|
|
||||||
- return biomesettingsmobs.d;
|
|
||||||
+ RecordCodecBuilder<MobSpawnSettings, Float> recordcodecbuilder = Codec.FLOAT.optionalFieldOf("creature_spawn_probability", 0.1F).forGetter((biomesettingsmobs) -> { // Paper - add type to builder
|
|
||||||
+ return biomesettingsmobs.creatureGenerationProbability;
|
|
||||||
});
|
|
||||||
- Codec codec = MobCategory.CODEC;
|
|
||||||
- Codec codec1 = BiomeSettingsMobs.c.b.listOf();
|
|
||||||
- Logger logger = MobSpawnSettings.LOGGER;
|
|
||||||
-
|
|
||||||
- logger.getClass();
|
|
||||||
- return instance.group(recordcodecbuilder, Codec.simpleMap(codec, codec1.promotePartial(Util.prefix("Spawn data: ", logger::error)), StringRepresentable.keys(MobCategory.values())).fieldOf("spawners").forGetter((biomesettingsmobs) -> {
|
|
||||||
- return biomesettingsmobs.e;
|
|
||||||
- }), Codec.simpleMap(Registry.ENTITY_TYPE, BiomeSettingsMobs.b.a, Registry.ENTITY_TYPE).fieldOf("spawn_costs").forGetter((biomesettingsmobs) -> {
|
|
||||||
- return biomesettingsmobs.f;
|
|
||||||
+ // Paper - remove unused vars
|
|
||||||
+
|
|
||||||
+ return instance.group(recordcodecbuilder, Codec.simpleMap(MobCategory.CODEC, cProxy.CODEC.listOf().promotePartial(Util.prefix("Spawn data: ", MobSpawnSettings.LOGGER::error)), StringRepresentable.keys(MobCategory.values())).fieldOf("spawners").forGetter((biomesettingsmobs) -> { // Paper - inline codec, cProxy, LOGGER
|
|
||||||
+ return biomesettingsmobs.spawners;
|
|
||||||
+ }), Codec.simpleMap(Registry.ENTITY_TYPE, bProxy.CODEC, Registry.ENTITY_TYPE).fieldOf("spawn_costs").forGetter((biomesettingsmobs) -> { // Paper - decompile error - bProxy
|
|
||||||
+ return biomesettingsmobs.mobSpawnCosts;
|
|
||||||
}), Codec.BOOL.fieldOf("player_spawn_friendly").orElse(false).forGetter(MobSpawnSettings::playerSpawnFriendly)).apply(instance, MobSpawnSettings::new);
|
|
||||||
});
|
|
||||||
private final float creatureGenerationProbability;
|
|
||||||
@@ -76,11 +85,43 @@ public class MobSpawnSettings {
|
|
||||||
|
|
||||||
public static class Builder {
|
|
||||||
|
|
||||||
- private final Map<MobCategory, List<MobSpawnSettings.SpawnerData>> spawners = (Map) Stream.of(MobCategory.values()).collect(ImmutableMap.toImmutableMap((enumcreaturetype) -> {
|
|
||||||
+ // Paper start - keep track of data in a pair set to give O(1) contains calls - we have to hook removals incase plugins mess with it
|
|
||||||
+ public static class MobList extends java.util.ArrayList<MobSpawnSettings.SpawnerData> {
|
|
||||||
+ java.util.Set<MobSpawnSettings.SpawnerData> biomes = new java.util.HashSet<>();
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean contains(Object o) {
|
|
||||||
+ return biomes.contains(o);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean add(MobSpawnSettings.SpawnerData BiomeSettingsMobs) {
|
|
||||||
+ biomes.add(BiomeSettingsMobs);
|
|
||||||
+ return super.add(BiomeSettingsMobs);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public MobSpawnSettings.SpawnerData remove(int index) {
|
|
||||||
+ MobSpawnSettings.SpawnerData removed = super.remove(index);
|
|
||||||
+ if (removed != null) {
|
|
||||||
+ biomes.remove(removed);
|
|
||||||
+ }
|
|
||||||
+ return removed;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public void clear() {
|
|
||||||
+ biomes.clear();
|
|
||||||
+ super.clear();
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // use toImmutableEnumMap collector
|
|
||||||
+ private final Map<MobCategory, List<MobSpawnSettings.SpawnerData>> spawners = (Map) Stream.of(MobCategory.values()).collect(Maps.toImmutableEnumMap((enumcreaturetype) -> {
|
|
||||||
return enumcreaturetype;
|
|
||||||
}, (enumcreaturetype) -> {
|
|
||||||
- return Lists.newArrayList();
|
|
||||||
+ return new MobList(); // Use MobList instead of ArrayList
|
|
||||||
}));
|
|
||||||
+ // Paper end
|
|
||||||
private final Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> mobSpawnCosts = Maps.newLinkedHashMap();
|
|
||||||
private float creatureGenerationProbability = 0.1F;
|
|
||||||
private boolean playerCanSpawn;
|
|
|
@ -1,31 +0,0 @@
|
||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Phoenix616 <mail@moep.tv>
|
|
||||||
Date: Tue, 18 Sep 2018 23:53:23 +0100
|
|
||||||
Subject: [PATCH] PreSpawnerSpawnEvent
|
|
||||||
|
|
||||||
This adds a separate event before an entity is spawned by a spawner
|
|
||||||
which contains the location of the spawner too similarly to how the
|
|
||||||
SpawnerSpawnEvent gets called instead of the CreatureSpawnEvent for
|
|
||||||
spawners.
|
|
||||||
|
|
||||||
Dropped as it does not apply due to the earlier PreCreatureSpawnEvent patch not being applied
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
|
||||||
index ac572eba10a7239d71dfae060f623b076d4252ce..1ce675d0d24ceb5724f5ac2d8f671e38f2735f74 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
|
||||||
@@ -132,11 +132,11 @@ public abstract class BaseSpawner {
|
|
||||||
|
|
||||||
org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(key);
|
|
||||||
if (type != null) {
|
|
||||||
- com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
|
|
||||||
- event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
|
||||||
+ com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event;
|
|
||||||
+ event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent(
|
|
||||||
MCUtil.toLocation(world, d3, d4, d5),
|
|
||||||
type,
|
|
||||||
- org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER
|
|
||||||
+ MCUtil.toLocation(world, blockposition)
|
|
||||||
);
|
|
||||||
if (!event.callEvent()) {
|
|
||||||
flag = true;
|
|
|
@ -1,117 +0,0 @@
|
||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Aikar <aikar@aikar.co>
|
|
||||||
Date: Fri, 29 May 2020 20:29:02 -0400
|
|
||||||
Subject: [PATCH] Synchronize DataPaletteBlock instead of ReentrantLock
|
|
||||||
1.17: Mini have fun I don't want to die
|
|
||||||
Mojang has flaws in their logic about chunks being concurrently
|
|
||||||
wrote to. So we constantly see crashes around multiple threads writing.
|
|
||||||
|
|
||||||
Additionally, java has optimized synchronization so well that its
|
|
||||||
in many times faster than trying to manage read wrote locks for low
|
|
||||||
contention situations.
|
|
||||||
|
|
||||||
And this is extremely a low contention situation.
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
||||||
index 6d3dcd19ce1abc9d502903b8008949b5174a13c3..917b0a64083ebbe24321089b784b91f3af4918b9 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
||||||
@@ -8,7 +8,6 @@ import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import net.minecraft.CrashReport;
|
|
||||||
-import net.minecraft.CrashReportCategory;
|
|
||||||
import net.minecraft.ReportedException;
|
|
||||||
import net.minecraft.core.IdMapper;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
@@ -32,23 +31,23 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
|
||||||
private int bits; private int getBitsPerObject() { return this.bits; } // Paper - OBFHELPER
|
|
||||||
private final ReentrantLock lock = new ReentrantLock();
|
|
||||||
|
|
||||||
- public void acquire() {
|
|
||||||
- if (this.lock.isLocked() && !this.lock.isHeldByCurrentThread()) {
|
|
||||||
+ public void acquire() { /* // Paper start - disable this - use proper synchronization
|
|
||||||
+ if (this.j.isLocked() && !this.j.isHeldByCurrentThread()) {
|
|
||||||
String s = (String) Thread.getAllStackTraces().keySet().stream().filter(Objects::nonNull).map((thread) -> {
|
|
||||||
return thread.getName() + ": \n\tat " + (String) Arrays.stream(thread.getStackTrace()).map(Object::toString).collect(Collectors.joining("\n\tat "));
|
|
||||||
}).collect(Collectors.joining("\n"));
|
|
||||||
CrashReport crashreport = new CrashReport("Writing into PalettedContainer from multiple threads", new IllegalStateException());
|
|
||||||
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Thread dumps");
|
|
||||||
+ CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Thread dumps");
|
|
||||||
|
|
||||||
- crashreportsystemdetails.setDetail("Thread dumps", (Object) s);
|
|
||||||
+ crashreportsystemdetails.a("Thread dumps", (Object) s);
|
|
||||||
throw new ReportedException(crashreport);
|
|
||||||
} else {
|
|
||||||
- this.lock.lock();
|
|
||||||
- }
|
|
||||||
+ this.j.lock();
|
|
||||||
+ } */ // Paper end
|
|
||||||
}
|
|
||||||
|
|
||||||
public void release() {
|
|
||||||
- this.lock.unlock();
|
|
||||||
+ //this.j.unlock(); // Paper - disable this
|
|
||||||
}
|
|
||||||
|
|
||||||
public PalettedContainer(Palette<T> fallbackPalette, IdMapper<T> idList, Function<CompoundTag, T> elementDeserializer, Function<T, CompoundTag> elementSerializer, T defaultElement) {
|
|
||||||
@@ -84,7 +83,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
- public int onResize(int newSize, T objectAdded) {
|
|
||||||
+ public synchronized int onResize(int newSize, T objectAdded) { // Paper - synchronize
|
|
||||||
this.acquire();
|
|
||||||
BitStorage databits = this.storage;
|
|
||||||
Palette<T> datapalette = this.palette;
|
|
||||||
@@ -107,18 +106,18 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getAndSet(int x, int y, int z, T value) {
|
|
||||||
- this.acquire();
|
|
||||||
- T t1 = this.getAndSet(getIndex(x, y, z), value);
|
|
||||||
+ //this.a(); // Paper - remove to reduce ops - synchronize handled below
|
|
||||||
+ return this.getAndSet(getIndex(x, y, z), value); // Paper
|
|
||||||
|
|
||||||
- this.release();
|
|
||||||
- return t1;
|
|
||||||
+ //this.b(); // Paper
|
|
||||||
+ //return t1; // PAper
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getAndSetUnchecked(int x, int y, int z, T value) {
|
|
||||||
return this.getAndSet(getIndex(x, y, z), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
- protected T getAndSet(int index, T value) {
|
|
||||||
+ protected synchronized T getAndSet(int index, T value) { // Paper - synchronize - writes
|
|
||||||
int j = this.palette.idFor(value);
|
|
||||||
int k = this.storage.getAndSet(index, j);
|
|
||||||
T t1 = this.palette.valueFor(k);
|
|
||||||
@@ -143,7 +142,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeDataPaletteBlock(FriendlyByteBuf packetDataSerializer) { this.write(packetDataSerializer); } // Paper - OBFHELPER
|
|
||||||
- public void write(FriendlyByteBuf buf) {
|
|
||||||
+ public synchronized void write(FriendlyByteBuf buf) { // Paper - synchronize
|
|
||||||
this.acquire();
|
|
||||||
buf.writeByte(this.bits);
|
|
||||||
this.palette.write(buf);
|
|
||||||
@@ -151,7 +150,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
|
||||||
this.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
- public void read(ListTag paletteTag, long[] data) {
|
|
||||||
+ public synchronized void read(ListTag paletteTag, long[] data) { // Paper - synchronize
|
|
||||||
this.acquire();
|
|
||||||
int i = Math.max(4, Mth.ceillog2(paletteTag.size()));
|
|
||||||
|
|
||||||
@@ -184,7 +183,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
|
||||||
this.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
- public void write(CompoundTag nbttagcompound, String s, String s1) {
|
|
||||||
+ public synchronized void write(CompoundTag nbttagcompound, String s, String s1) { // Paper - synchronize
|
|
||||||
this.acquire();
|
|
||||||
HashMapPalette<T> datapalettehash = new HashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer);
|
|
||||||
T t0 = this.defaultValue;
|
|
29
patches/server/0290-PreSpawnerSpawnEvent.patch
Normal file
29
patches/server/0290-PreSpawnerSpawnEvent.patch
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Phoenix616 <mail@moep.tv>
|
||||||
|
Date: Tue, 18 Sep 2018 23:53:23 +0100
|
||||||
|
Subject: [PATCH] PreSpawnerSpawnEvent
|
||||||
|
|
||||||
|
This adds a separate event before an entity is spawned by a spawner
|
||||||
|
which contains the location of the spawner too similarly to how the
|
||||||
|
SpawnerSpawnEvent gets called instead of the CreatureSpawnEvent for
|
||||||
|
spawners.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||||
|
index c741f8e4a4b67d1bfed2d1bac36856c5688bb161..9228c0bc797fb95c8ac949bdc568eadafee84a80 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||||
|
@@ -138,11 +138,11 @@ public abstract class BaseSpawner {
|
||||||
|
|
||||||
|
org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(key);
|
||||||
|
if (type != null) {
|
||||||
|
- com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
|
||||||
|
- event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||||
|
+ com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event;
|
||||||
|
+ event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent(
|
||||||
|
net.minecraft.server.MCUtil.toLocation(world, d0, d1, d2),
|
||||||
|
type,
|
||||||
|
- org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER
|
||||||
|
+ net.minecraft.server.MCUtil.toLocation(world, pos)
|
||||||
|
);
|
||||||
|
if (!event.callEvent()) {
|
||||||
|
flag = true;
|
|
@ -0,0 +1,92 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Fri, 29 May 2020 20:29:02 -0400
|
||||||
|
Subject: [PATCH] Synchronize PalettedContainer instead of ReentrantLock
|
||||||
|
|
||||||
|
Mojang has flaws in their logic about chunks being concurrently
|
||||||
|
wrote to. So we constantly see crashes around multiple threads writing.
|
||||||
|
|
||||||
|
Additionally, java has optimized synchronization so well that its
|
||||||
|
in many times faster than trying to manage read wrote locks for low
|
||||||
|
contention situations.
|
||||||
|
|
||||||
|
And this is extremely a low contention situation.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||||
|
index 5ac948b5b82f3144cdf402af440251cb8c7369d7..d8b7a7d9aa3ef47aa4e222c6ca85e83ce21f2444 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||||
|
@@ -36,16 +36,18 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
||||||
|
private final DebugBuffer<Pair<Thread, StackTraceElement[]>> traces = null;
|
||||||
|
|
||||||
|
public void acquire() {
|
||||||
|
+ /* // Paper start - disable this - use proper synchronization
|
||||||
|
if (this.traces != null) {
|
||||||
|
Thread thread = Thread.currentThread();
|
||||||
|
this.traces.push(Pair.of(thread, thread.getStackTrace()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadingDetector.checkAndLock(this.lock, this.traces, "PalettedContainer");
|
||||||
|
+ */ // Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
- this.lock.release();
|
||||||
|
+ //this.lock.release(); // Paper - disable this
|
||||||
|
}
|
||||||
|
|
||||||
|
public PalettedContainer(Palette<T> fallbackPalette, IdMapper<T> idList, Function<CompoundTag, T> elementDeserializer, Function<T, CompoundTag> elementSerializer, T defaultElement) {
|
||||||
|
@@ -96,7 +98,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
||||||
|
return this.palette.idFor(objectAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
- public T getAndSet(int x, int y, int z, T value) {
|
||||||
|
+ public synchronized T getAndSet(int x, int y, int z, T value) { // Paper - synchronize
|
||||||
|
Object var6;
|
||||||
|
try {
|
||||||
|
this.acquire();
|
||||||
|
@@ -120,7 +122,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
||||||
|
return (T)(object == null ? this.defaultValue : object);
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void set(int i, int j, int k, T object) {
|
||||||
|
+ public synchronized void set(int i, int j, int k, T object) { // Paper - synchronize
|
||||||
|
try {
|
||||||
|
this.acquire();
|
||||||
|
this.set(getIndex(i, j, k), object);
|
||||||
|
@@ -144,7 +146,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
||||||
|
return (T)(object == null ? this.defaultValue : object);
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void read(FriendlyByteBuf buf) {
|
||||||
|
+ public synchronized void read(FriendlyByteBuf buf) { // Paper - synchronize
|
||||||
|
try {
|
||||||
|
this.acquire();
|
||||||
|
int i = buf.readByte();
|
||||||
|
@@ -161,7 +163,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeDataPaletteBlock(FriendlyByteBuf packetDataSerializer) { this.write(packetDataSerializer); } // Paper - OBFHELPER
|
||||||
|
- public void write(FriendlyByteBuf buf) {
|
||||||
|
+ public synchronized void write(FriendlyByteBuf buf) { // Paper - synchronize
|
||||||
|
try {
|
||||||
|
this.acquire();
|
||||||
|
buf.writeByte(this.bits);
|
||||||
|
@@ -173,7 +175,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void read(ListTag paletteNbt, long[] data) {
|
||||||
|
+ public synchronized void read(ListTag paletteNbt, long[] data) { // Paper - synchronize
|
||||||
|
try {
|
||||||
|
this.acquire();
|
||||||
|
int i = Math.max(4, Mth.ceillog2(paletteNbt.size()));
|
||||||
|
@@ -206,7 +208,7 @@ public class PalettedContainer<T> implements PaletteResize<T> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void write(CompoundTag nbt, String paletteKey, String dataKey) {
|
||||||
|
+ public synchronized void write(CompoundTag nbt, String paletteKey, String dataKey) { // Paper - synchronize
|
||||||
|
try {
|
||||||
|
this.acquire();
|
||||||
|
HashMapPalette<T> hashMapPalette = new HashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer);
|
|
@ -0,0 +1,57 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Wed, 12 Sep 2018 21:47:01 -0400
|
||||||
|
Subject: [PATCH] Optimize Biome Mob Lookups for Mob Spawning
|
||||||
|
|
||||||
|
Uses an EnumMap as well as a Set paired List for O(1) contains calls.
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java
|
||||||
|
index 4e06bb1fbda33e79044ac54758b559f7436882a7..86528ff031014e788d72a8bf7c1c9443512096bb 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java
|
||||||
|
@@ -70,11 +70,43 @@ public class MobSpawnSettings {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
- private final Map<MobCategory, List<MobSpawnSettings.SpawnerData>> spawners = Stream.of(MobCategory.values()).collect(ImmutableMap.toImmutableMap((mobCategory) -> {
|
||||||
|
+ // Paper start - keep track of data in a pair set to give O(1) contains calls - we have to hook removals incase plugins mess with it
|
||||||
|
+ public static class MobList extends java.util.ArrayList<MobSpawnSettings.SpawnerData> {
|
||||||
|
+ java.util.Set<MobSpawnSettings.SpawnerData> biomes = new java.util.HashSet<>();
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean contains(Object o) {
|
||||||
|
+ return biomes.contains(o);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean add(MobSpawnSettings.SpawnerData BiomeSettingsMobs) {
|
||||||
|
+ biomes.add(BiomeSettingsMobs);
|
||||||
|
+ return super.add(BiomeSettingsMobs);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public MobSpawnSettings.SpawnerData remove(int index) {
|
||||||
|
+ MobSpawnSettings.SpawnerData removed = super.remove(index);
|
||||||
|
+ if (removed != null) {
|
||||||
|
+ biomes.remove(removed);
|
||||||
|
+ }
|
||||||
|
+ return removed;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void clear() {
|
||||||
|
+ biomes.clear();
|
||||||
|
+ super.clear();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // use toImmutableEnumMap collector
|
||||||
|
+ private final Map<MobCategory, List<MobSpawnSettings.SpawnerData>> spawners = (Map) Stream.of(MobCategory.values()).collect(Maps.toImmutableEnumMap((mobCategory) -> {
|
||||||
|
return mobCategory;
|
||||||
|
}, (mobCategory) -> {
|
||||||
|
- return Lists.newArrayList();
|
||||||
|
+ return new MobList(); // Use MobList instead of ArrayList
|
||||||
|
}));
|
||||||
|
+ // Paper end
|
||||||
|
private final Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> mobSpawnCosts = Maps.newLinkedHashMap();
|
||||||
|
private float creatureGenerationProbability = 0.1F;
|
||||||
|
private boolean playerCanSpawn;
|
Loading…
Reference in a new issue