Paper/Spigot-Server-Patches/0528-Fix-Concurrency-issue-in-WeightedList.patch
Riley Park 4e958e229f
We're going on an Adventure! (#4842)
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: zml <zml@stellardrift.ca>
Co-authored-by: Mariell Hoversholm <proximyst@proximyst.com>
2021-02-21 20:45:33 +01:00

149 lines
6.5 KiB
Diff

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 WeightedList
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/server/BehaviorGate.java b/src/main/java/net/minecraft/server/BehaviorGate.java
index 4a5b54b44958b7eddaf2cd7bd517647cca96fd62..46e910581210421c8699637431804dc2f43eb4a6 100644
--- a/src/main/java/net/minecraft/server/BehaviorGate.java
+++ b/src/main/java/net/minecraft/server/BehaviorGate.java
@@ -12,7 +12,7 @@ public class BehaviorGate<E extends EntityLiving> extends Behavior<E> {
private final Set<MemoryModuleType<?>> b;
private final BehaviorGate.Order c;
private final BehaviorGate.Execution d;
- private final WeightedList<Behavior<? super E>> e = new WeightedList<>();
+ private final WeightedList<Behavior<? super E>> e = new WeightedList<>(false); // Paper - don't use a clone
public BehaviorGate(Map<MemoryModuleType<?>, MemoryStatus> map, Set<MemoryModuleType<?>> set, BehaviorGate.Order behaviorgate_order, BehaviorGate.Execution behaviorgate_execution, List<Pair<Behavior<? super E>, Integer>> list) {
super(map);
@@ -60,10 +60,9 @@ public class BehaviorGate<E extends EntityLiving> extends Behavior<E> {
}).forEach((behavior) -> {
behavior.g(worldserver, e0, i);
});
- Set set = this.b;
BehaviorController behaviorcontroller = e0.getBehaviorController();
- set.forEach(behaviorcontroller::removeMemory);
+ this.b.forEach(behaviorcontroller::removeMemory); // Paper - decomp fix
}
@Override
@@ -110,7 +109,7 @@ public class BehaviorGate<E extends EntityLiving> extends Behavior<E> {
private final Consumer<WeightedList<?>> c;
- private Order(Consumer consumer) {
+ private Order(Consumer<WeightedList<?>> consumer) { // Paper - decomp fix
this.c = consumer;
}
diff --git a/src/main/java/net/minecraft/server/WeightedList.java b/src/main/java/net/minecraft/server/WeightedList.java
index 73e5969b2a15f1639b6285286820e9f7871c7db8..5d9d58411f2fad9d5da703f964d269b4a7c2b205 100644
--- a/src/main/java/net/minecraft/server/WeightedList.java
+++ b/src/main/java/net/minecraft/server/WeightedList.java
@@ -6,7 +6,7 @@ import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.DynamicOps;
-import com.mojang.serialization.OptionalDynamic;
+
import java.util.Comparator;
import java.util.List;
import java.util.Random;
@@ -14,26 +14,32 @@ import java.util.stream.Stream;
public class WeightedList<U> {
- protected final List<WeightedList.a<U>> a;
+ protected final List<WeightedList.a<U>> list; // Paper - decompile conflict
private final Random b;
+ private final boolean isUnsafe; // Paper
- public WeightedList() {
- this(Lists.newArrayList());
+ // Paper start - add useClone option
+ public WeightedList() { this(true); }
+ public WeightedList(boolean isUnsafe) {
+ this(Lists.newArrayList(), isUnsafe);
}
- private WeightedList(List<WeightedList.a<U>> list) {
+ private WeightedList(List<WeightedList.a<U>> list) { this(list, true); }
+ private WeightedList(List<WeightedList.a<U>> list, boolean isUnsafe) {
+ this.isUnsafe = isUnsafe;
+ // Paper end
this.b = new Random();
- this.a = Lists.newArrayList(list);
+ this.list = Lists.newArrayList(list); // Paper - decompile conflict
}
public static <U> Codec<WeightedList<U>> a(Codec<U> codec) {
- return WeightedList.a.a(codec).listOf().xmap(WeightedList::new, (weightedlist) -> {
- return weightedlist.a;
+ return WeightedList.a.a(codec).listOf().xmap(WeightedList::new, (weightedlist) -> { // Paper - decompile conflict
+ return weightedlist.list; // Paper - decompile conflict
});
}
public WeightedList<U> a(U u0, int i) {
- this.a.add(new WeightedList.a<>(u0, i));
+ this.list.add(new WeightedList.a<>(u0, i)); // Paper - decompile conflict
return this;
}
@@ -42,21 +48,20 @@ public class WeightedList<U> {
}
public WeightedList<U> a(Random random) {
- this.a.forEach((weightedlist_a) -> {
- weightedlist_a.a(random.nextFloat());
- });
- this.a.sort(Comparator.comparingDouble((object) -> {
- return ((WeightedList.a) object).c();
- }));
- return this;
+ // Paper start - make concurrent safe, work off a clone of the list
+ List<WeightedList.a<U>> list = isUnsafe ? new java.util.ArrayList<WeightedList.a<U>>(this.list) : this.list;
+ list.forEach((weightedlist_a) -> weightedlist_a.a(random.nextFloat()));
+ list.sort(Comparator.comparingDouble(a::c));
+ return isUnsafe ? new WeightedList<>(list, isUnsafe) : this;
+ // Paper end
}
public boolean b() {
- return this.a.isEmpty();
+ return this.list.isEmpty(); // Paper - decompile conflict
}
public Stream<U> c() {
- return this.a.stream().map(WeightedList.a::a);
+ return this.list.stream().map(WeightedList.a::a); // Paper - decompile conflict
}
public U b(Random random) {
@@ -64,7 +69,7 @@ public class WeightedList<U> {
}
public String toString() {
- return "WeightedList[" + this.a + "]";
+ return "WeightedList[" + this.list + "]"; // Paper - decompile conflict
}
public static class a<T> {
@@ -98,11 +103,7 @@ public class WeightedList<U> {
return new Codec<WeightedList.a<E>>() {
public <T> DataResult<Pair<WeightedList.a<E>, T>> decode(DynamicOps<T> dynamicops, T t0) {
Dynamic<T> dynamic = new Dynamic(dynamicops, t0);
- OptionalDynamic optionaldynamic = dynamic.get("data");
- Codec codec1 = codec;
-
- codec.getClass();
- return optionaldynamic.flatMap(codec1::parse).map((object) -> {
+ return dynamic.get("data").flatMap(codec::parse).map((object) -> { // Paper - decompile error
return new WeightedList.a<>(object, dynamic.get("weight").asInt(1));
}).map((weightedlist_a) -> {
return Pair.of(weightedlist_a, dynamicops.empty());