From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar <aikar@aikar.co> 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. diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java index 334962f1bf5988059fec506f0d3aaf4302205220..6a270c9adb044a6e0b1c8e09b9106d51989fd761 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java @@ -18,7 +18,7 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E> private final Set<MemoryModuleType<?>> exitErasedMemories; private final GateBehavior.OrderPolicy orderPolicy; private final GateBehavior.RunningPolicy runningPolicy; - private final ShufflingList<BehaviorControl<? super E>> behaviors = new ShufflingList<>(); + private final ShufflingList<BehaviorControl<? super E>> behaviors = new ShufflingList<>(false); // Paper - Fix Concurrency issue in ShufflingList during worldgen private Behavior.Status status = Behavior.Status.STOPPED; public GateBehavior( diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java index 195eea55fabc7a9a665e0a8f04934a3aaf9f8b71..3fac11bf02652b5f51f30f99bdf516504467d0d2 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java @@ -16,12 +16,25 @@ import net.minecraft.util.RandomSource; public class ShufflingList<U> implements Iterable<U> { protected final List<ShufflingList.WeightedEntry<U>> 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<ShufflingList.WeightedEntry<U>> list) { + // Paper start - Fix Concurrency issue in ShufflingList during worldgen + this(list, true); + } + private ShufflingList(List<ShufflingList.WeightedEntry<U>> 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 class ShufflingList<U> implements Iterable<U> { } public ShufflingList<U> 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<ShufflingList.WeightedEntry<U>> 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<U> stream() {