From 1d8508b7ac2f243fb819e1b6b5bb88db7c60054f Mon Sep 17 00:00:00 2001 From: Aikar Date: Mon, 6 Jul 2020 18:36:41 -0400 Subject: [PATCH] Fix Concurrency issue in ShufflingList if multiple threads from worldgen sort at same time, it will crash. So make a copy of the list for sorting purposes. --- .../ai/behavior/GateBehavior.java.patch | 11 +++++ .../ai/behavior/ShufflingList.java.patch | 44 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GateBehavior.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ShufflingList.java.patch diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GateBehavior.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GateBehavior.java.patch new file mode 100644 index 0000000000..fdb4490626 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/GateBehavior.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java ++++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java +@@ -18,7 +18,7 @@ + private final Set> exitErasedMemories; + private final GateBehavior.OrderPolicy orderPolicy; + private final GateBehavior.RunningPolicy runningPolicy; +- private final ShufflingList> behaviors = new ShufflingList<>(); ++ private final ShufflingList> behaviors = new ShufflingList<>(false); // Paper - Fix Concurrency issue in ShufflingList during worldgen + private Behavior.Status status = Behavior.Status.STOPPED; + + public GateBehavior( diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ShufflingList.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ShufflingList.java.patch new file mode 100644 index 0000000000..3f1d97092e --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/ShufflingList.java.patch @@ -0,0 +1,44 @@ +--- a/net/minecraft/world/entity/ai/behavior/ShufflingList.java ++++ b/net/minecraft/world/entity/ai/behavior/ShufflingList.java +@@ -16,12 +16,25 @@ + public class ShufflingList implements Iterable { + protected final List> entries; + private final RandomSource random = RandomSource.create(); ++ private final boolean isUnsafe; // Paper - Fix Concurrency issue in ShufflingList during worldgen + + public ShufflingList() { ++ // Paper start - Fix Concurrency issue in ShufflingList during worldgen ++ this(true); ++ } ++ public ShufflingList(boolean isUnsafe) { ++ this.isUnsafe = isUnsafe; ++ // Paper end - Fix Concurrency issue in ShufflingList during worldgen + this.entries = Lists.newArrayList(); + } + + private ShufflingList(List> list) { ++ // Paper start - Fix Concurrency issue in ShufflingList during worldgen ++ this(list, true); ++ } ++ private ShufflingList(List> list, boolean isUnsafe) { ++ this.isUnsafe = isUnsafe; ++ // Paper end - Fix Concurrency issue in ShufflingList during worldgen + this.entries = Lists.newArrayList(list); + } + +@@ -35,9 +48,12 @@ + } + + public ShufflingList shuffle() { +- this.entries.forEach(entry -> entry.setRandom(this.random.nextFloat())); +- this.entries.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight)); +- return this; ++ // Paper start - Fix Concurrency issue in ShufflingList during worldgen ++ List> list = this.isUnsafe ? Lists.newArrayList(this.entries) : this.entries; ++ list.forEach(entry -> entry.setRandom(this.random.nextFloat())); ++ list.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight)); ++ return this.isUnsafe ? new ShufflingList<>(list, this.isUnsafe) : this; ++ // Paper end - Fix Concurrency issue in ShufflingList during worldgen + } + + public Stream stream() {