mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-28 07:20:24 +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