9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-23 08:59:23 +00:00

Updated Upstream (Hearse)

This commit is contained in:
Dreeam
2023-01-08 18:47:00 -05:00
parent 4450699caf
commit cbb2c88c77
35 changed files with 23614 additions and 8151 deletions

View File

@@ -18,6 +18,7 @@
- Disabling the UseItemOnPacket Too Far check.
- Update all dependencies to the latest.
- Parallel entity ticking(Half of async)(In alpha)
- Parallel world ticking
- Some Purpur patches.
- ...
@@ -64,4 +65,4 @@ Credits:
- [Petal](https://github.com/Bloom-host/Petal)
- [Carpet Fixes](https://github.com/fxmorin/carpet-fixes)
- [VMP](https://github.com/RelativityMC/VMP-fabric)
- [Hearse](https://github.com/NaturalCodeClub/Hearse)
- [Hearse](https://github.com/NaturalCodeClub/HearseRewrite)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,203 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Sun, 8 Jan 2023 21:14:07 +0800
Subject: [PATCH] Hearse: Pathfiner changes
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java b/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
index 27b9cefc172b391824ead382a712b8b9b1ddfe45..4b65331a9192b7ac75141183493126ee730e697e 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
@@ -4,9 +4,9 @@ public class BinaryHeap {
private Node[] heap = new Node[128];
private int size;
- public Node insert(Node node) {
+ public synchronized Node insert(Node node) {
if (node.heapIdx >= 0) {
- throw new IllegalStateException("OW KNOWS!");
+ return node;
} else {
if (this.size == this.heap.length) {
Node[] nodes = new Node[this.size << 1];
@@ -21,15 +21,15 @@ public class BinaryHeap {
}
}
- public void clear() {
+ public synchronized void clear() {
this.size = 0;
}
- public Node peek() {
+ public synchronized Node peek() {
return this.heap[0];
}
- public Node pop() {
+ public synchronized Node pop() {
Node node = this.heap[0];
this.heap[0] = this.heap[--this.size];
this.heap[this.size] = null;
@@ -41,7 +41,7 @@ public class BinaryHeap {
return node;
}
- public void remove(Node node) {
+ public synchronized void remove(Node node) {
this.heap[node.heapIdx] = this.heap[--this.size];
this.heap[this.size] = null;
if (this.size > node.heapIdx) {
@@ -55,7 +55,7 @@ public class BinaryHeap {
node.heapIdx = -1;
}
- public void changeCost(Node node, float weight) {
+ public synchronized void changeCost(Node node, float weight) {
float f = node.f;
node.f = weight;
if (weight < f) {
@@ -66,11 +66,14 @@ public class BinaryHeap {
}
- public int size() {
+ public synchronized int size() {
return this.size;
}
private void upHeap(int index) {
+ if(index == -1){
+ return;
+ }
Node node = this.heap[index];
int i;
@@ -90,6 +93,9 @@ public class BinaryHeap {
}
private void downHeap(int index) {
+ if(index == -1){
+ return;
+ }
Node node = this.heap[index];
float f = node.f;
@@ -135,11 +141,11 @@ public class BinaryHeap {
node.heapIdx = index;
}
- public boolean isEmpty() {
+ public synchronized boolean isEmpty() {
return this.size == 0;
}
- public Node[] getHeap() {
+ public synchronized Node[] getHeap() {
Node[] nodes = new Node[this.size()];
System.arraycopy(this.heap, 0, nodes, 0, this.size());
return nodes;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java
index b0bae04ab5a93dd4cf1eeeb02bed1e508e1f2913..d427735eff0056c171591709829d0bb76f7bb6f3 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java
@@ -1,6 +1,7 @@
package net.minecraft.world.level.pathfinder;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.util.EnumSet;
import java.util.List;
@@ -15,7 +16,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
public class FlyNodeEvaluator extends WalkNodeEvaluator {
- private final Long2ObjectMap<BlockPathTypes> pathTypeByPosCache = new Long2ObjectOpenHashMap<>();
+ private final Long2ObjectMap<BlockPathTypes> pathTypeByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
private static final float SMALL_MOB_INFLATED_START_NODE_BOUNDING_BOX = 1.5F;
private static final int MAX_START_NODE_CANDIDATES = 10;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
index a8a2594b8f5b3ebf6a1f918c7d822ad35b051b17..c614bcfc2bbbbccc7c4aac9389d4780478e739d2 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
@@ -1,6 +1,7 @@
package net.minecraft.world.level.pathfinder;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
@@ -11,7 +12,7 @@ import net.minecraft.world.level.PathNavigationRegion;
public abstract class NodeEvaluator {
protected PathNavigationRegion level;
protected Mob mob;
- protected final Int2ObjectMap<Node> nodes = new Int2ObjectOpenHashMap<>();
+ protected final Int2ObjectMap<Node> nodes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
protected int entityWidth;
protected int entityHeight;
protected int entityDepth;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
index a8af51a25b0f99c3a64d9150fdfcd6b818aa7581..cd2592552339a79361d2a4e7936731330e15f6fa 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
@@ -31,7 +31,7 @@ public class PathFinder {
}
@Nullable
- public Path findPath(PathNavigationRegion world, Mob mob, Set<BlockPos> positions, float followRange, int distance, float rangeMultiplier) {
+ public synchronized Path findPath(PathNavigationRegion world, Mob mob, Set<BlockPos> positions, float followRange, int distance, float rangeMultiplier) {
this.openSet.clear();
this.nodeEvaluator.prepare(world, mob);
Node node = this.nodeEvaluator.getStart();
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
index 6084631b5b502279b84f190dc62fc76b770e368e..f526adbd31e65fc74af48f6137d293a7a7ceafbb 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
@@ -2,6 +2,7 @@ package net.minecraft.world.level.pathfinder;
import com.google.common.collect.Maps;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.util.Map;
import javax.annotation.Nullable;
@@ -17,7 +18,7 @@ import net.minecraft.world.level.material.FluidState;
public class SwimNodeEvaluator extends NodeEvaluator {
private final boolean allowBreaching;
- private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = new Long2ObjectOpenHashMap<>();
+ private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
public SwimNodeEvaluator(boolean canJumpOutOfWater) {
this.allowBreaching = canJumpOutOfWater;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
index 894881018c659d874f28f5744f0b8247cfecb1c1..ae06f7ef9c4b8147508984f8b46176de46171285 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
@@ -1,8 +1,10 @@
package net.minecraft.world.level.pathfinder;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
+import it.unimi.dsi.fastutil.objects.Object2BooleanMaps;
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
import java.util.EnumSet;
import javax.annotation.Nullable;
@@ -33,8 +35,8 @@ public class WalkNodeEvaluator extends NodeEvaluator {
public static final double SPACE_BETWEEN_WALL_POSTS = 0.5D;
private static final double DEFAULT_MOB_JUMP_HEIGHT = 1.125D;
protected float oldWaterCost;
- private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = new Long2ObjectOpenHashMap<>();
- private final Object2BooleanMap<AABB> collisionCache = new Object2BooleanOpenHashMap<>();
+ private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
+ private final Object2BooleanMap<AABB> collisionCache = Object2BooleanMaps.synchronize(new Object2BooleanOpenHashMap<>());
@Override
public void prepare(PathNavigationRegion cachedWorld, Mob entity) {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,386 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Sun, 8 Jan 2023 21:59:47 +0800
Subject: [PATCH] Hearse: MC code changes 2
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 03b8ef3409fd5f7a4d4b06e13cf8eb22b3bbf8a1..3d99330160a3ba0715394d0c88533bc4a79fe3a2 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -3,10 +3,12 @@ package net.minecraft.server.level;
import com.google.common.annotations.VisibleForTesting;
import co.aikar.timings.TimingHistory; // Paper
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.util.Pair;
import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.longs.LongSets;
@@ -21,15 +23,8 @@ import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.UUID;
+import java.util.*;
+import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.Executor;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
@@ -204,7 +199,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
final Set<Mob> navigatingMobs;
volatile boolean isUpdatingNavigations;
protected final Raids raids;
- private final ObjectLinkedOpenHashSet<BlockEventData> blockEvents;
+ private final Deque<BlockEventData> blockEvents;
private final List<BlockEventData> blockEventsToReschedule;
private boolean handlingTick;
private final List<CustomSpawner> customSpawners;
@@ -536,10 +531,10 @@ public class ServerLevel extends Level implements WorldGenLevel {
this.entityTickList = new EntityTickList();
this.blockTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded, this.getProfilerSupplier());
this.fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded, this.getProfilerSupplier());
- this.navigatingMobs = new ObjectOpenHashSet();
- this.blockEvents = new ObjectLinkedOpenHashSet();
- this.blockEventsToReschedule = new ArrayList(64);
- this.dragonParts = new Int2ObjectOpenHashMap();
+ this.navigatingMobs = Sets.newConcurrentHashSet();
+ this.blockEvents = new ConcurrentLinkedDeque<>();
+ this.blockEventsToReschedule = Collections.synchronizedList(new ArrayList(64));
+ this.dragonParts = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap());
this.tickTime = flag1;
this.server = minecraftserver;
this.customSpawners = list;
@@ -1777,10 +1772,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
private void runBlockEvents() {
this.blockEventsToReschedule.clear();
-
- while (!this.blockEvents.isEmpty()) {
- BlockEventData blockactiondata = (BlockEventData) this.blockEvents.removeFirst();
-
+ BlockEventData blockactiondata;
+ while ((blockactiondata = (BlockEventData) this.blockEvents.pollFirst())!=null) {
if (this.shouldTickBlocksAt(blockactiondata.pos())) {
if (this.doBlockEvent(blockactiondata)) {
this.server.getPlayerList().broadcast((Player) null, (double) blockactiondata.pos().getX(), (double) blockactiondata.pos().getY(), (double) blockactiondata.pos().getZ(), 64.0D, this.dimension(), new ClientboundBlockEventPacket(blockactiondata.pos(), blockactiondata.block(), blockactiondata.paramA(), blockactiondata.paramB()));
diff --git a/src/main/java/net/minecraft/util/ThreadingDetector.java b/src/main/java/net/minecraft/util/ThreadingDetector.java
index b6e98aaebe57453b8eceaa633a989aa24409830f..60162cccf765800c6172d1544f2cd9bcf30cbd97 100644
--- a/src/main/java/net/minecraft/util/ThreadingDetector.java
+++ b/src/main/java/net/minecraft/util/ThreadingDetector.java
@@ -17,7 +17,7 @@ import org.slf4j.Logger;
public class ThreadingDetector {
private static final Logger LOGGER = LogUtils.getLogger();
private final String name;
- private final Semaphore lock = new Semaphore(1);
+ private final Semaphore lock = new Semaphore(255);
private final Lock stackTraceLock = new ReentrantLock();
@Nullable
private volatile Thread threadThatFailedToAcquire;
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java b/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java
index d3827215ef19f6e1e63f846d91ed00525a318c7a..80215972538d5cfce5f224253ea0e34ea4fd45a4 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java
@@ -40,7 +40,7 @@ public class LongJumpToRandomPos<E extends Mob> extends Behavior<E> {
protected final int maxLongJumpHeight;
protected final int maxLongJumpWidth;
protected final float maxJumpVelocity;
- protected List<LongJumpToRandomPos.PossibleJump> jumpCandidates = Lists.newArrayList();
+ protected List<LongJumpToRandomPos.PossibleJump> jumpCandidates = Lists.newCopyOnWriteArrayList();
protected Optional<Vec3> initialPosition = Optional.empty();
@Nullable
protected Vec3 chosenJump;
diff --git a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
index 878a42695ecedf0c3f2e6310e3ce44c6b6c36858..0c308e12f9b590fa169babac487c8adc7e3f823c 100644
--- a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
+++ b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
@@ -2,18 +2,17 @@ package net.minecraft.world.level.gameevent;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
+
+import java.util.*;
+
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.phys.Vec3;
public class EuclideanGameEventListenerRegistry implements GameEventListenerRegistry {
- private final List<GameEventListener> listeners = Lists.newArrayList();
- private final Set<GameEventListener> listenersToRemove = Sets.newHashSet();
- private final List<GameEventListener> listenersToAdd = Lists.newArrayList();
+ private final List<GameEventListener> listeners = Collections.synchronizedList(Lists.newArrayList());
+ private final Set<GameEventListener> listenersToRemove = Sets.newConcurrentHashSet();
+ private final List<GameEventListener> listenersToAdd = Lists.newCopyOnWriteArrayList();
private boolean processing;
private final ServerLevel level;
diff --git a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java
index ac807277a6b26d140ea9873d17c7aa4fb5fe37b2..4c75f50ab0184637b72e08936ff8808ad6c6fb5f 100644
--- a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java
+++ b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java
@@ -13,6 +13,8 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.annotation.Nullable;
+
+import it.unimi.dsi.fastutil.objects.ObjectSets;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.level.ChunkPos;
@@ -21,7 +23,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
private final Queue<ScheduledTick<T>> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER);
@Nullable
private List<SavedTick<T>> pendingTicks;
- private final Set<ScheduledTick<?>> ticksPerPosition = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
+ private final Set<ScheduledTick<?>> ticksPerPosition = ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH));
@Nullable
private BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> onTickAdded;
@@ -29,11 +31,11 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
private boolean dirty;
private long lastSaved = Long.MIN_VALUE;
- public boolean isDirty(final long tick) {
+ public synchronized boolean isDirty(final long tick) {
return this.dirty || (!this.tickQueue.isEmpty() && tick != this.lastSaved);
}
- public void clearDirty() {
+ public synchronized void clearDirty() {
this.dirty = false;
}
// Paper end - add dirty flag
@@ -50,17 +52,17 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
- public void setOnTickAdded(@Nullable BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> tickConsumer) {
+ public synchronized void setOnTickAdded(@Nullable BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> tickConsumer) {
this.onTickAdded = tickConsumer;
}
@Nullable
- public ScheduledTick<T> peek() {
+ public synchronized ScheduledTick<T> peek() {
return this.tickQueue.peek();
}
@Nullable
- public ScheduledTick<T> poll() {
+ public synchronized ScheduledTick<T> poll() {
ScheduledTick<T> scheduledTick = this.tickQueue.poll();
if (scheduledTick != null) {
this.dirty = true; // Paper - add dirty flag
@@ -71,7 +73,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
@Override
- public void schedule(ScheduledTick<T> orderedTick) {
+ public synchronized void schedule(ScheduledTick<T> orderedTick) {
if (this.ticksPerPosition.add(orderedTick)) {
this.dirty = true; // Paper - add dirty flag
this.scheduleUnchecked(orderedTick);
@@ -88,11 +90,11 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
@Override
- public boolean hasScheduledTick(BlockPos pos, T type) {
+ public synchronized boolean hasScheduledTick(BlockPos pos, T type) {
return this.ticksPerPosition.contains(ScheduledTick.probe(type, pos));
}
- public void removeIf(Predicate<ScheduledTick<T>> predicate) {
+ public synchronized void removeIf(Predicate<ScheduledTick<T>> predicate) {
Iterator<ScheduledTick<T>> iterator = this.tickQueue.iterator();
while(iterator.hasNext()) {
@@ -105,17 +107,17 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
- public Stream<ScheduledTick<T>> getAll() {
+ public synchronized Stream<ScheduledTick<T>> getAll() {
return this.tickQueue.stream();
}
@Override
- public int count() {
+ public synchronized int count() {
return this.tickQueue.size() + (this.pendingTicks != null ? this.pendingTicks.size() : 0);
}
@Override
- public ListTag save(long l, Function<T, String> function) {
+ public synchronized ListTag save(long l, Function<T, String> function) {
this.lastSaved = l; // Paper - add dirty system to level ticks
ListTag listTag = new ListTag();
if (this.pendingTicks != null) {
@@ -131,7 +133,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
return listTag;
}
- public void unpack(long time) {
+ public synchronized void unpack(long time) {
if (this.pendingTicks != null) {
// Paper start - add dirty system to level chunk ticks
if (this.tickQueue.isEmpty()) {
diff --git a/src/main/java/net/minecraft/world/ticks/LevelTicks.java b/src/main/java/net/minecraft/world/ticks/LevelTicks.java
index 5dea8414964e0d2d1fb15a6baa27227e9722bfc7..2203adc2a68e7fb253e353098fd6ddad521e3a32 100644
--- a/src/main/java/net/minecraft/world/ticks/LevelTicks.java
+++ b/src/main/java/net/minecraft/world/ticks/LevelTicks.java
@@ -1,24 +1,9 @@
package net.minecraft.world.ticks;
-import it.unimi.dsi.fastutil.longs.Long2LongMap;
-import it.unimi.dsi.fastutil.longs.Long2LongMaps;
-import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.longs.*;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.LongSummaryStatistics;
-import java.util.PriorityQueue;
-import java.util.Queue;
-import java.util.Set;
-import java.util.function.BiConsumer;
-import java.util.function.LongPredicate;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
+import it.unimi.dsi.fastutil.objects.ObjectSets;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
@@ -26,31 +11,36 @@ import net.minecraft.core.Vec3i;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
+import java.util.*;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.BiConsumer;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
public class LevelTicks<T> implements LevelTickAccess<T> {
private static final Comparator<LevelChunkTicks<?>> CONTAINER_DRAIN_ORDER = (a, b) -> {
return ScheduledTick.INTRA_TICK_DRAIN_ORDER.compare(a.peek(), b.peek());
};
private final LongPredicate tickCheck;
- private final Supplier<ProfilerFiller> profiler;
- private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = new Long2ObjectOpenHashMap<>();
+ private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
private final Long2LongMap nextTickForContainer = Util.make(new Long2LongOpenHashMap(), (map) -> {
map.defaultReturnValue(Long.MAX_VALUE);
});
private final Queue<LevelChunkTicks<T>> containersToTick = new PriorityQueue<>(CONTAINER_DRAIN_ORDER);
- private final Queue<ScheduledTick<T>> toRunThisTick = new ArrayDeque<>();
- private final List<ScheduledTick<T>> alreadyRunThisTick = new ArrayList<>();
- private final Set<ScheduledTick<?>> toRunThisTickSet = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
+ private final Queue<ScheduledTick<T>> toRunThisTick = new ConcurrentLinkedDeque<>();
+ private final List<ScheduledTick<T>> alreadyRunThisTick = new CopyOnWriteArrayList<>();
+ private final Set<ScheduledTick<?>> toRunThisTickSet = ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH));
+
private final BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> chunkScheduleUpdater = (chunkTickScheduler, tick) -> {
if (tick.equals(chunkTickScheduler.peek())) {
this.updateContainerScheduling(tick);
}
-
};
public LevelTicks(LongPredicate tickingFutureReadyPredicate, Supplier<ProfilerFiller> profilerGetter) {
this.tickCheck = tickingFutureReadyPredicate;
- this.profiler = profilerGetter;
}
public void addContainer(ChunkPos pos, LevelChunkTicks<T> scheduler) {
@@ -123,7 +113,9 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
entry.setValue(scheduledTick.triggerTick());
} else if (this.tickCheck.test(l)) {
objectIterator.remove();
- this.containersToTick.add(levelChunkTicks);
+ synchronized (this.containersToTick){
+ this.containersToTick.add(levelChunkTicks);
+ }
}
}
}
@@ -133,27 +125,29 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
private void drainContainers(long time, int maxTicks) {
LevelChunkTicks<T> levelChunkTicks;
- while(this.canScheduleMoreTicks(maxTicks) && (levelChunkTicks = this.containersToTick.poll()) != null) {
- ScheduledTick<T> scheduledTick = levelChunkTicks.poll();
- this.scheduleForThisTick(scheduledTick);
- this.drainFromCurrentContainer(this.containersToTick, levelChunkTicks, time, maxTicks);
- ScheduledTick<T> scheduledTick2 = levelChunkTicks.peek();
- if (scheduledTick2 != null) {
- if (scheduledTick2.triggerTick() <= time && this.canScheduleMoreTicks(maxTicks)) {
- this.containersToTick.add(levelChunkTicks);
- } else {
- this.updateContainerScheduling(scheduledTick2);
+ synchronized (this.containersToTick){
+ while(this.canScheduleMoreTicks(maxTicks) && (levelChunkTicks = this.containersToTick.poll()) != null) {
+ ScheduledTick<T> scheduledTick = levelChunkTicks.poll();
+ this.scheduleForThisTick(scheduledTick);
+ this.drainFromCurrentContainer(this.containersToTick, levelChunkTicks, time, maxTicks);
+ ScheduledTick<T> scheduledTick2 = levelChunkTicks.peek();
+ if (scheduledTick2 != null) {
+ if (scheduledTick2.triggerTick() <= time && this.canScheduleMoreTicks(maxTicks)) {
+ this.containersToTick.add(levelChunkTicks);
+ } else {
+ this.updateContainerScheduling(scheduledTick2);
+ }
}
}
}
-
}
private void rescheduleLeftoverContainers() {
- for(LevelChunkTicks<T> levelChunkTicks : this.containersToTick) {
- this.updateContainerScheduling(levelChunkTicks.peek());
+ synchronized (this.containersToTick){
+ for(LevelChunkTicks<T> levelChunkTicks : this.containersToTick) {
+ this.updateContainerScheduling(levelChunkTicks.peek());
+ }
}
-
}
private void updateContainerScheduling(ScheduledTick<T> tick) {
@@ -201,7 +195,9 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
private void cleanupAfterTick() {
this.toRunThisTick.clear();
- this.containersToTick.clear();
+ synchronized (this.containersToTick){
+ this.containersToTick.clear();
+ }
this.alreadyRunThisTick.clear();
this.toRunThisTickSet.clear();
}

View File

@@ -0,0 +1,394 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Sun, 8 Jan 2023 22:12:06 +0800
Subject: [PATCH] Hearse: Add base codes
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/HearseConfig.java b/src/main/java/co/earthme/hearse/HearseConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..912da4787f83f656da67e9533b60183c17e6c345
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/HearseConfig.java
@@ -0,0 +1,4 @@
+package co.earthme.hearse;
+
+public class HearseConfig {
+}
diff --git a/src/main/java/co/earthme/hearse/concurrent/ThreadPool.java b/src/main/java/co/earthme/hearse/concurrent/ThreadPool.java
new file mode 100644
index 0000000000000000000000000000000000000000..3fbc81cb880cf6d38bb4c940b4cc1fa828c2ef17
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/concurrent/ThreadPool.java
@@ -0,0 +1,76 @@
+package co.earthme.hearse.concurrent;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Queue;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.LockSupport;
+
+public class ThreadPool extends ThreadPoolExecutor {
+ public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
+ }
+
+ public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull ThreadFactory threadFactory) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
+ }
+
+ public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull RejectedExecutionHandler handler) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
+ }
+
+ public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull ThreadFactory threadFactory, @NotNull RejectedExecutionHandler handler) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
+ }
+
+ private final Queue<TaskEntry> taskEntries = new ConcurrentLinkedQueue<>();
+
+ public void executeWithSubTask(Runnable mainTask,Runnable subTask){
+ final TaskEntry wrapped = new TaskEntry(subTask,mainTask);
+ this.taskEntries.offer(wrapped);
+ this.execute(wrapped);
+ }
+
+ public void runAllSubTasks(){
+ TaskEntry task;
+ while ((task = this.taskEntries.poll())!=null){
+ while (!task.allRunned()){
+ LockSupport.parkNanos(this,10000000);
+ }
+ }
+ }
+
+ private static class TaskEntry implements Runnable{
+ private final Runnable mainTask;
+ private final Runnable subTask;
+ private volatile boolean mainTaskFinished = false;
+
+ public TaskEntry(Runnable subTask,Runnable mainTask){
+ this.subTask = subTask;
+ this.mainTask = mainTask;
+ }
+
+ public boolean allRunned(){
+ if (!this.mainTaskFinished){
+ return false;
+ }
+ try {
+ this.subTask.run();
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ return true;
+ }
+
+ @Override
+ public void run() {
+ try {
+ this.mainTask.run();
+ }catch(Exception e){
+ e.printStackTrace();
+ }finally {
+ this.mainTaskFinished = true;
+ }
+ }
+ }
+}
diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..06f55f26eb63e356b3558622bf68711f18cda1c6
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
@@ -0,0 +1,13 @@
+package co.earthme.hearse.concurrent;
+
+import io.papermc.paper.util.TickThread;
+
+public class WorkerThread extends TickThread {
+ public WorkerThread(String name) {
+ super(name);
+ }
+
+ public static boolean isWorker(){
+ return Thread.currentThread() instanceof WorkerThread;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 3d99330160a3ba0715394d0c88533bc4a79fe3a2..30cde5b9cd8d179f4b332563f2999f675851fbd1 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1,64 +1,33 @@
package net.minecraft.server.level;
+import co.aikar.timings.TimingHistory;
import com.google.common.annotations.VisibleForTesting;
-import co.aikar.timings.TimingHistory; // Paper
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.util.Pair;
import com.mojang.logging.LogUtils;
+import io.papermc.paper.util.MCUtil;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.longs.LongSets;
import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
-import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
-import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.*;
-import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.concurrent.Executor;
-import java.util.function.BooleanSupplier;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import net.minecraft.CrashReport;
import net.minecraft.Util;
-import net.minecraft.core.BlockPos;
-import net.minecraft.core.Direction;
-import net.minecraft.core.Holder;
-import net.minecraft.core.HolderSet;
-import net.minecraft.core.RegistryAccess;
-import net.minecraft.core.SectionPos;
+import net.minecraft.core.*;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
-import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.protocol.Packet;
-import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket;
-import net.minecraft.network.protocol.game.ClientboundBlockEventPacket;
-import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
-import net.minecraft.network.protocol.game.ClientboundExplodePacket;
-import net.minecraft.network.protocol.game.ClientboundLevelEventPacket;
-import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket;
-import net.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacket;
-import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket;
-import net.minecraft.network.protocol.game.ClientboundSoundPacket;
-import net.minecraft.network.protocol.game.DebugPackets;
+import net.minecraft.network.protocol.game.*;
import net.minecraft.resources.ResourceKey;
-import io.papermc.paper.util.MCUtil;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerScoreboard;
import net.minecraft.server.level.progress.ChunkProgressListener;
@@ -66,21 +35,10 @@ import net.minecraft.server.players.SleepStatus;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.TagKey;
-import net.minecraft.util.AbortableIterationConsumer;
-import net.minecraft.util.CsvOutput;
-import net.minecraft.util.Mth;
-import net.minecraft.util.ProgressListener;
-import net.minecraft.util.Unit;
-import net.minecraft.util.profiling.ProfilerFiller;
+import net.minecraft.util.*;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.damagesource.DamageSource;
-import net.minecraft.world.entity.Entity;
-import net.minecraft.world.entity.EntityType;
-import net.minecraft.world.entity.LightningBolt;
-import net.minecraft.world.entity.LivingEntity;
-import net.minecraft.world.entity.Mob;
-import net.minecraft.world.entity.MobCategory;
-import net.minecraft.world.entity.ReputationEventHandler;
+import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.ai.village.ReputationEventType;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
@@ -97,17 +55,7 @@ import net.minecraft.world.entity.raid.Raid;
import net.minecraft.world.entity.raid.Raids;
import net.minecraft.world.flag.FeatureFlagSet;
import net.minecraft.world.item.crafting.RecipeManager;
-import net.minecraft.world.level.BlockEventData;
-import net.minecraft.world.level.ChunkPos;
-import net.minecraft.world.level.CustomSpawner;
-import net.minecraft.world.level.Explosion;
-import net.minecraft.world.level.ExplosionDamageCalculator;
-import net.minecraft.world.level.ForcedChunksSavedData;
-import net.minecraft.world.level.GameRules;
-import net.minecraft.world.level.Level;
-import net.minecraft.world.level.NaturalSpawner;
-import net.minecraft.world.level.StructureManager;
-import net.minecraft.world.level.WorldGenLevel;
+import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.block.Block;
@@ -123,12 +71,10 @@ import net.minecraft.world.level.chunk.storage.EntityStorage;
import net.minecraft.world.level.dimension.BuiltinDimensionTypes;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.dimension.end.EndDragonFight;
-import net.minecraft.world.level.entity.EntityPersistentStorage;
import net.minecraft.world.level.entity.EntityTickList;
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.level.entity.LevelCallback;
import net.minecraft.world.level.entity.LevelEntityGetter;
-import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import net.minecraft.world.level.gameevent.DynamicGameEventListener;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.gameevent.GameEventDispatcher;
@@ -153,21 +99,32 @@ import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.ticks.LevelTicks;
-import org.slf4j.Logger;
import org.bukkit.Bukkit;
-import org.bukkit.Location;
import org.bukkit.WeatherType;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.craftbukkit.generator.CustomWorldChunkManager;
-import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.util.WorldUUID;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.server.MapInitializeEvent;
import org.bukkit.event.weather.LightningStrikeEvent;
-import org.bukkit.event.world.GenericGameEvent;
import org.bukkit.event.world.TimeSkipEvent;
-// CraftBukkit end
-import it.unimi.dsi.fastutil.ints.IntArrayList; // Paper
+import org.slf4j.Logger;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.Executor;
+import java.util.function.BooleanSupplier;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
public class ServerLevel extends Level implements WorldGenLevel {
@@ -988,7 +945,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
if (this.canSleepThroughNights()) {
if (!this.getServer().isSingleplayer() || this.getServer().isPublished()) {
int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
- MutableComponent ichatmutablecomponent;
+ Component ichatmutablecomponent;
if (this.sleepStatus.areEnoughSleeping(i)) {
ichatmutablecomponent = Component.translatable("sleep.skipping_night");
@@ -1656,56 +1613,56 @@ public class ServerLevel extends Level implements WorldGenLevel {
@Override
public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) {
- if (this.isUpdatingNavigations) {
- String s = "recursive call to sendBlockUpdated";
+ synchronized (this.navigatingMobs){
+ if (this.isUpdatingNavigations) {
+ return;
+ }
- Util.logAndPauseIfInIde("recursive call to sendBlockUpdated", new IllegalStateException("recursive call to sendBlockUpdated"));
- }
+ this.getChunkSource().blockChanged(pos);
+ if(this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates
+ VoxelShape voxelshape = oldState.getCollisionShape(this, pos);
+ VoxelShape voxelshape1 = newState.getCollisionShape(this, pos);
- this.getChunkSource().blockChanged(pos);
- if(this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates
- VoxelShape voxelshape = oldState.getCollisionShape(this, pos);
- VoxelShape voxelshape1 = newState.getCollisionShape(this, pos);
+ if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) {
+ List<PathNavigation> list = new ObjectArrayList();
+ Iterator iterator = this.navigatingMobs.iterator();
- if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) {
- List<PathNavigation> list = new ObjectArrayList();
- Iterator iterator = this.navigatingMobs.iterator();
+ while (iterator.hasNext()) {
+ // CraftBukkit start - fix SPIGOT-6362
+ Mob entityinsentient;
+ try {
+ entityinsentient = (Mob) iterator.next();
+ } catch (java.util.ConcurrentModificationException ex) {
+ // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register
+ // In this case we just run the update again across all the iterators as the chunk will then be loaded
+ // As this is a relative edge case it is much faster than copying navigators (on either read or write)
+ this.sendBlockUpdated(pos, oldState, newState, flags);
+ return;
+ }
+ // CraftBukkit end
+ PathNavigation navigationabstract = entityinsentient.getNavigation();
- while (iterator.hasNext()) {
- // CraftBukkit start - fix SPIGOT-6362
- Mob entityinsentient;
- try {
- entityinsentient = (Mob) iterator.next();
- } catch (java.util.ConcurrentModificationException ex) {
- // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register
- // In this case we just run the update again across all the iterators as the chunk will then be loaded
- // As this is a relative edge case it is much faster than copying navigators (on either read or write)
- this.sendBlockUpdated(pos, oldState, newState, flags);
- return;
- }
- // CraftBukkit end
- PathNavigation navigationabstract = entityinsentient.getNavigation();
+ if (navigationabstract.shouldRecomputePath(pos)) {
+ list.add(navigationabstract);
+ }
+ }
- if (navigationabstract.shouldRecomputePath(pos)) {
- list.add(navigationabstract);
- }
- }
+ try {
+ this.isUpdatingNavigations = true;
+ iterator = list.iterator();
- try {
- this.isUpdatingNavigations = true;
- iterator = list.iterator();
+ while (iterator.hasNext()) {
+ PathNavigation navigationabstract1 = (PathNavigation) iterator.next();
- while (iterator.hasNext()) {
- PathNavigation navigationabstract1 = (PathNavigation) iterator.next();
+ navigationabstract1.recomputePath();
+ }
+ } finally {
+ this.isUpdatingNavigations = false;
+ }
- navigationabstract1.recomputePath();
}
- } finally {
- this.isUpdatingNavigations = false;
- }
-
+ } // Paper
}
- } // Paper
}
@Override

View File

@@ -0,0 +1,315 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Mon, 9 Jan 2023 09:26:38 +0800
Subject: [PATCH] Hearse: Update codes
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
index 06f55f26eb63e356b3558622bf68711f18cda1c6..2a43625d13d7aa253c15aba8092ac9361785a5f0 100644
--- a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
+++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
@@ -3,8 +3,11 @@ package co.earthme.hearse.concurrent;
import io.papermc.paper.util.TickThread;
public class WorkerThread extends TickThread {
+
public WorkerThread(String name) {
super(name);
+ this.setDaemon(true);
+ this.setPriority(Thread.NORM_PRIORITY - 2);
}
public static boolean isWorker(){
diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThreadFactory.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..e65b1eba68003a9f7ce5080d07a521817831ff48
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadFactory.java
@@ -0,0 +1,5 @@
+package co.earthme.hearse.concurrent;
+
+public interface WorkerThreadFactory {
+ WorkerThread getNewThread(Runnable task);
+}
diff --git a/src/main/java/co/earthme/hearse/concurrent/ThreadPool.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java
similarity index 62%
rename from src/main/java/co/earthme/hearse/concurrent/ThreadPool.java
rename to src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java
index 3fbc81cb880cf6d38bb4c940b4cc1fa828c2ef17..f7ca6d650d9089b65137d61acca64c89e5b4db22 100644
--- a/src/main/java/co/earthme/hearse/concurrent/ThreadPool.java
+++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java
@@ -6,25 +6,17 @@ import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.locks.LockSupport;
-public class ThreadPool extends ThreadPoolExecutor {
- public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue) {
- super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
- }
-
- public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull ThreadFactory threadFactory) {
- super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
- }
+public class WorkerThreadPoolExecutor extends ThreadPoolExecutor {
+ private final Queue<TaskEntry> taskEntries = new ConcurrentLinkedQueue<>();
- public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull RejectedExecutionHandler handler) {
- super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
+ public WorkerThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull WorkerThreadFactory workerThreadFactory) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,r->workerThreadFactory.getNewThread(r));
}
- public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull ThreadFactory threadFactory, @NotNull RejectedExecutionHandler handler) {
- super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
+ public WorkerThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull WorkerThreadFactory workerThreadFactory, @NotNull RejectedExecutionHandler handler) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,r->workerThreadFactory.getNewThread(r), handler);
}
- private final Queue<TaskEntry> taskEntries = new ConcurrentLinkedQueue<>();
-
public void executeWithSubTask(Runnable mainTask,Runnable subTask){
final TaskEntry wrapped = new TaskEntry(subTask,mainTask);
this.taskEntries.offer(wrapped);
diff --git a/src/main/java/co/earthme/hearse/server/ServerHook.java b/src/main/java/co/earthme/hearse/server/ServerHook.java
new file mode 100644
index 0000000000000000000000000000000000000000..22260735664d986fed6bf82e4016b647417e1932
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/server/ServerHook.java
@@ -0,0 +1,66 @@
+package co.earthme.hearse.server;
+
+import co.earthme.hearse.concurrent.WorkerThread;
+import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.entity.Entity;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ServerHook {
+ private static volatile boolean firstTick = false;
+ private static final AtomicInteger threadId = new AtomicInteger();
+ private static final WorkerThreadPoolExecutor worker = new WorkerThreadPoolExecutor(
+ Runtime.getRuntime().availableProcessors(),
+ Runtime.getRuntime().availableProcessors(),
+ 100,
+ TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<>(),
+ task -> {
+ WorkerThread workerThread = new WorkerThread("Hearse-Worker-Thread # "+threadId.getAndIncrement());
+ return workerThread;
+ }
+ );
+
+ public static void executeAsyncTask(Runnable task){
+ worker.execute(task);
+ }
+
+ public static void executeAsyncTaskWithMainThreadCallback(Runnable task,Runnable callBack){
+ worker.executeWithSubTask(task,callBack);
+ }
+
+ public static void callPostTick(){
+ if (!firstTick){
+ firstTick = true;
+ return;
+ }
+ worker.runAllSubTasks();
+ }
+
+ public static void callAsyncEntityTick(Entity entity, ServerLevel level){
+ MinecraftServer.getServer().executeMidTickTasks();
+ worker.execute(()->{
+ entity.activatedPriorityReset = false;
+ if (!entity.isRemoved()) {
+ entity.checkDespawn();
+ Entity entity1 = entity.getVehicle();
+ if (entity1 != null) {
+ if (!entity1.isRemoved() && entity1.hasPassenger(entity)) {
+ return;
+ }
+ entity.stopRiding();
+ }
+ try {
+ level.tickNonPassenger(entity);
+ } catch (Throwable throwable) {
+ if (throwable instanceof ThreadDeath) throw throwable;
+ level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(throwable.getMessage(), throwable)));
+ throwable.printStackTrace();
+ }
+ }
+ });
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 3b7e4b724e86518ea57f5ed5ef0b8b3741d10f6f..e0e169a4403926ff6be004de1bf5ec2079acb440 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1,5 +1,6 @@
package net.minecraft.server;
+import co.earthme.hearse.server.ServerHook;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import co.aikar.timings.Timings;
@@ -1407,6 +1408,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
++this.tickCount;
this.tickChildren(shouldKeepTicking);
+ ServerHook.callPostTick();
if (i - this.lastServerStatus >= 5000000000L) {
this.lastServerStatus = i;
this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount()));
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index a2935994edc279d880ff26dd5cc4e33f1105acc8..81697ea6d00967852556c3bb741317db030c24db 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -833,12 +833,10 @@ public class ServerChunkCache extends ChunkSource {
if (chunkMap.playerMobDistanceMap != null && _pufferfish_spawnCountsReady.getAndSet(false)) {
net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> {
int mapped = distanceManager.getNaturalSpawnChunkCount();
- io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator<Entity> objectiterator =
- level.entityTickList.entities.iterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS);
+ Iterator<Entity> objectiterator = level.entityTickList.entities.iterator();
gg.pufferfish.pufferfish.util.IterableWrapper<Entity> wrappedIterator =
new gg.pufferfish.pufferfish.util.IterableWrapper<>(objectiterator);
lastSpawnState = NaturalSpawner.createState(mapped, wrappedIterator, this::getFullChunk, null, true);
- objectiterator.finishedIterating();
_pufferfish_spawnCountsReady.set(true);
});
}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 6074956d677542a46066dc45ceda9d73a2e09d27..125e5fb54acb68d58ea9fb973894b02facb04edc 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1,6 +1,8 @@
package net.minecraft.server.level;
import co.aikar.timings.TimingHistory;
+import co.earthme.hearse.concurrent.WorkerThread;
+import co.earthme.hearse.server.ServerHook;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -221,7 +223,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
public final void loadChunksForMoveAsync(AABB axisalignedbb, ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority,
java.util.function.Consumer<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) {
- if (Thread.currentThread() != this.thread) {
+ if (Thread.currentThread() != this.thread && !WorkerThread.isWorker()) {
this.getChunkSource().mainThreadProcessor.execute(() -> {
this.loadChunksForMoveAsync(axisalignedbb, priority, onLoad);
});
@@ -643,71 +645,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
//timings.doSounds.stopTiming(); // Spigot // Purpur
this.handlingTick = false;
//gameprofilerfiller.pop(); // Purpur
- boolean flag = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
-
- if (flag) {
- this.resetEmptyTime();
- }
-
- if (flag || this.emptyTime++ < 300) {
- //gameprofilerfiller.push("entities"); // Purpur
- //timings.tickEntities.startTiming(); // Spigot // Purpur
- if (this.dragonFight != null) {
- //gameprofilerfiller.push("dragonFight"); // Purpur
- this.dragonFight.tick();
- //gameprofilerfiller.pop(); // Purpur
- }
-
- org.spigotmc.ActivationRange.activateEntities(this); // Spigot
- //timings.entityTick.startTiming(); // Spigot // Purpur
- this.entityTickList.forEach((entity) -> {
- entity.activatedPriorityReset = false; // Pufferfish - DAB
- if (!entity.isRemoved()) {
- if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed
- entity.discard();
- } else {
- //gameprofilerfiller.push("checkDespawn"); // Purpur
- entity.checkDespawn();
- //gameprofilerfiller.pop(); // Purpur
- if (true || this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { // Paper - now always true if in the ticking list
- Entity entity1 = entity.getVehicle();
-
- if (entity1 != null) {
- if (!entity1.isRemoved() && entity1.hasPassenger(entity)) {
- return;
- }
-
- entity.stopRiding();
- }
-
- //gameprofilerfiller.push("tick"); // Purpur
- // Pufferfish start - copied from this.guardEntityTick
- try {
- this.tickNonPassenger(entity); // Pufferfish - changed
- MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick
- } catch (Throwable throwable) {
- if (throwable instanceof ThreadDeath) throw throwable; // Paper
- // Paper start - Prevent tile entity and entity crashes
- final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
- MinecraftServer.LOGGER.error(msg, throwable);
- getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable)));
- entity.discard();
- // Paper end
- }
- // Pufferfish end
- //gameprofilerfiller.pop(); // Purpur
- }
- }
- }
- });
- //timings.entityTick.stopTiming(); // Spigot // Purpur
- //timings.tickEntities.stopTiming(); // Spigot // Purpur
- //gameprofilerfiller.pop(); // Purpur
- this.tickBlockEntities();
+ this.resetEmptyTime();
+ if (this.dragonFight != null) {
+ this.dragonFight.tick();
}
-
- //gameprofilerfiller.push("entityManagement"); // Purpur
- //this.entityManager.tick(); // Paper - rewrite chunk system
+ org.spigotmc.ActivationRange.activateEntities(this); // Spigot
+ this.entityTickList.forEach((entity) -> {
+ ServerHook.callAsyncEntityTick(entity,this);
+ });
+ this.tickBlockEntities();
}
@Override
@@ -746,7 +692,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
- private boolean shouldDiscardEntity(Entity entity) {
+ public boolean shouldDiscardEntity(Entity entity) {
return !this.server.isSpawningAnimals() && (entity instanceof Animal || entity instanceof WaterAnimal) ? true : !this.server.areNpcsEnabled() && entity instanceof Npc;
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 958e0ee29915bddde2cb8ebfd578448b83e2b149..de78c5bdde53b4adfed9fda4d473560849bdb5aa 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -2,6 +2,7 @@ package net.minecraft.world.level;
import co.aikar.timings.Timing;
import co.aikar.timings.Timings;
+import co.earthme.hearse.concurrent.WorkerThread;
import com.destroystokyo.paper.event.server.ServerExceptionEvent;
import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.base.MoreObjects;
@@ -1116,7 +1117,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
}
// Paper end
// CraftBukkit end
- return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !io.papermc.paper.util.TickThread.isTickThread() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system
+ return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !io.papermc.paper.util.TickThread.isTickThread() && !WorkerThread.isWorker() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system
}
public void setBlockEntity(BlockEntity blockEntity) {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Mon, 9 Jan 2023 12:40:56 +0800
Subject: [PATCH] Hearse: Fix some problems in ItemEntity
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/HearseConfig.java b/src/main/java/co/earthme/hearse/HearseConfig.java
index 912da4787f83f656da67e9533b60183c17e6c345..0a1de52bcdf675b9bfcbf14d39959818a7a0cbbb 100644
--- a/src/main/java/co/earthme/hearse/HearseConfig.java
+++ b/src/main/java/co/earthme/hearse/HearseConfig.java
@@ -1,4 +1,5 @@
package co.earthme.hearse;
public class HearseConfig {
+
}
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
index c58496c84b2b3f86890050813041fa49711f3a01..3e8b68b4390a6086b1b1983fe6f8b545c2847ef8 100644
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
@@ -4,6 +4,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nullable;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
@@ -239,21 +241,24 @@ public class ItemEntity extends Entity {
this.setDeltaMovement(vec3d.x * 0.949999988079071D, vec3d.y + (double) (vec3d.y < 0.05999999865889549D ? 5.0E-4F : 0.0F), vec3d.z * 0.949999988079071D);
}
+ private final Lock mergeLock = new ReentrantLock();
+
private void mergeWithNeighbours() {
- if (this.isMergable()) {
- // Spigot start
- double radius = level.spigotConfig.itemMerge;
- List<ItemEntity> list = this.level.getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, radius - 0.5D, radius), (entityitem) -> {
- // Spigot end
- return entityitem != this && entityitem.isMergable();
- });
- Iterator iterator = list.iterator();
-
- while (iterator.hasNext()) {
- ItemEntity entityitem = (ItemEntity) iterator.next();
-
- if (entityitem.isMergable()) {
- // Paper Start - Fix items merging through walls
+ if (!this.mergeLock.tryLock()){
+ return;
+ }
+ try {
+ if (this.isMergable()) {
+ // Spigot start
+ double radius = level.spigotConfig.itemMerge;
+ List<ItemEntity> list = this.level.getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, radius - 0.5D, radius), (entityitem) -> {
+ // Spigot end
+ return entityitem != this && entityitem.isMergable();
+ });
+
+ for (ItemEntity entityitem : list) {
+ if (entityitem.isMergable()) {
+ // Paper Start - Fix items merging through walls
if (this.level.paperConfig().fixes.fixItemsMergingThroughWalls) {
// Pufferfish start - skip the allocations
/*
@@ -263,17 +268,19 @@ public class ItemEntity extends Entity {
if (rayTraceResult.getType() == net.minecraft.world.phys.HitResult.Type.BLOCK) continue;
*/
if (level.rayTraceDirect(this.position(), entityitem.position(), net.minecraft.world.phys.shapes.CollisionContext.of(this)) ==
- net.minecraft.world.phys.HitResult.Type.BLOCK) continue;
+ net.minecraft.world.phys.HitResult.Type.BLOCK) continue;
// Pufferfish end
}
- // Paper End
- this.tryToMerge(entityitem);
- if (this.isRemoved()) {
- break;
+ // Paper End
+ this.tryToMerge(entityitem);
+ if (this.isRemoved()) {
+ break;
+ }
}
}
}
-
+ }finally {
+ this.mergeLock.unlock();
}
}

View File

@@ -0,0 +1,185 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Mon, 9 Jan 2023 13:15:09 +0800
Subject: [PATCH] Hearse: Fix some problems in GoalSelector and ShufflingList
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java b/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
index b3329c6fcd6758a781a51f5ba8f5052ac1c77b49..adb02cba6cdb62752f847136000c6f7ca857bd5a 100644
--- a/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
+++ b/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
@@ -2,9 +2,6 @@ package com.destroystokyo.paper.util.set;
import java.util.Collection;
-/**
- * @author Spottedleaf <Spottedleaf@users.noreply.github.com>
- */
public final class OptimizedSmallEnumSet<E extends Enum<E>> {
private final Class<E> enumClass;
@@ -20,7 +17,7 @@ public final class OptimizedSmallEnumSet<E extends Enum<E>> {
this.enumClass = clazz;
}
- public boolean addUnchecked(final E element) {
+ public synchronized boolean addUnchecked(final E element) {
final int ordinal = element.ordinal();
final long key = 1L << ordinal;
@@ -30,7 +27,7 @@ public final class OptimizedSmallEnumSet<E extends Enum<E>> {
return (prev & key) == 0;
}
- public boolean removeUnchecked(final E element) {
+ public synchronized boolean removeUnchecked(final E element) {
final int ordinal = element.ordinal();
final long key = 1L << ordinal;
@@ -40,15 +37,15 @@ public final class OptimizedSmallEnumSet<E extends Enum<E>> {
return (prev & key) != 0;
}
- public void clear() {
+ public synchronized void clear() {
this.backingSet = 0L;
}
- public int size() {
+ public synchronized int size() {
return Long.bitCount(this.backingSet);
}
- public void addAllUnchecked(final Collection<E> enums) {
+ public synchronized void addAllUnchecked(final Collection<E> enums) {
for (final E element : enums) {
if (element == null) {
throw new NullPointerException("Null element");
@@ -57,15 +54,15 @@ public final class OptimizedSmallEnumSet<E extends Enum<E>> {
}
}
- public long getBackingSet() {
+ public synchronized long getBackingSet() {
return this.backingSet;
}
- public boolean hasCommonElements(final OptimizedSmallEnumSet<E> other) {
+ public synchronized boolean hasCommonElements(final OptimizedSmallEnumSet<E> other) {
return (other.backingSet & this.backingSet) != 0;
}
- public boolean hasElement(final E element) {
+ public synchronized boolean hasElement(final E element) {
return (this.backingSet & (1L << element.ordinal())) != 0;
}
}
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 fe3ab3d388f0481fb0db06b7f730f868dbf8e8a5..ac006bacbe8715e5c272c69afd1edab45a6511e8 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
@@ -25,7 +25,7 @@ public class ShufflingList<U> implements Iterable<U> {
public ShufflingList(boolean isUnsafe) {
this.isUnsafe = isUnsafe;
// Paper end
- this.entries = Lists.newArrayList();
+ this.entries = Lists.newCopyOnWriteArrayList();
}
private ShufflingList(List<ShufflingList.WeightedEntry<U>> list) {
@@ -35,7 +35,7 @@ public class ShufflingList<U> implements Iterable<U> {
private ShufflingList(List<ShufflingList.WeightedEntry<U>> list, boolean isUnsafe) {
this.isUnsafe = isUnsafe;
// Paper end
- this.entries = Lists.newArrayList(list);
+ this.entries = Lists.newCopyOnWriteArrayList(list);
}
public static <U> Codec<ShufflingList<U>> codec(Codec<U> codec) {
@@ -44,12 +44,12 @@ public class ShufflingList<U> implements Iterable<U> {
});
}
- public ShufflingList<U> add(U data, int weight) {
+ public synchronized ShufflingList<U> add(U data, int weight) {
this.entries.add(new ShufflingList.WeightedEntry<>(data, weight));
return this;
}
- public ShufflingList<U> shuffle() {
+ public synchronized ShufflingList<U> shuffle() {
// Paper start - make concurrent safe, work off a clone of the list
List<ShufflingList.WeightedEntry<U>> list = this.isUnsafe ? Lists.newArrayList(this.entries) : this.entries;
list.forEach(entry -> entry.setRandom(this.random.nextFloat()));
@@ -58,17 +58,17 @@ public class ShufflingList<U> implements Iterable<U> {
// Paper end
}
- public Stream<U> stream() {
+ public synchronized Stream<U> stream() {
return this.entries.stream().map(ShufflingList.WeightedEntry::getData);
}
@Override
- public Iterator<U> iterator() {
+ public synchronized Iterator<U> iterator() {
return Iterators.transform(this.entries.iterator(), ShufflingList.WeightedEntry::getData);
}
@Override
- public String toString() {
+ public synchronized String toString() {
return "ShufflingList[" + this.entries + "]";
}
@@ -90,16 +90,16 @@ public class ShufflingList<U> implements Iterable<U> {
this.randWeight = -Math.pow((double)random, (double)(1.0F / (float)this.weight));
}
- public T getData() {
+ public synchronized T getData() {
return this.data;
}
- public int getWeight() {
+ public synchronized int getWeight() {
return this.weight;
}
@Override
- public String toString() {
+ public synchronized String toString() {
return this.weight + ":" + this.data;
}
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
index 02978315bc2b828cc603ce7478408f3f82c249c2..96d37e0845df9b22cf60f9835787789d0d0e4a79 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -3,11 +3,8 @@ package net.minecraft.world.entity.ai.goal;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets;
import com.mojang.logging.LogUtils;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
+
+import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -27,8 +24,8 @@ public class GoalSelector {
return false;
}
};
- private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
- private final Set<WrappedGoal> availableGoals = Sets.newLinkedHashSet();
+ private final Map<Goal.Flag, WrappedGoal> lockedFlags = Collections.synchronizedMap(new EnumMap<>(Goal.Flag.class));
+ private final Set<WrappedGoal> availableGoals = Sets.newCopyOnWriteArraySet();
private final Supplier<ProfilerFiller> profiler;
private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Mon, 9 Jan 2023 13:30:48 +0800
Subject: [PATCH] Hearse: Fix an UOE in GoalSelector
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index a23379120ddc3653b58bdb08f9c837c60b6b83ca..dfb747eba6bf7088af0ff400da169de00a076365 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1136,8 +1136,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot
// Paper start - ignore and warn about illegal addEntity calls instead of crashing server
if (!entity.valid || entity.level != this.level || this.entityMap.containsKey(entity.getId())) {
- LOGGER.error("Illegal ChunkMap::addEntity for world " + this.level.getWorld().getName()
- + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable());
+ LOGGER.error("Illegal ChunkMap::addEntity for world " + this.level.getWorld().getName() + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""));
return;
}
if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Delay adding to tracker until after list packets
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
index 96d37e0845df9b22cf60f9835787789d0d0e4a79..99142f749371828f6f55e4fbab03b22eb519ec1e 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -25,7 +25,7 @@ public class GoalSelector {
}
};
private final Map<Goal.Flag, WrappedGoal> lockedFlags = Collections.synchronizedMap(new EnumMap<>(Goal.Flag.class));
- private final Set<WrappedGoal> availableGoals = Sets.newCopyOnWriteArraySet();
+ private final Set<WrappedGoal> availableGoals = Sets.newConcurrentHashSet();
private final Supplier<ProfilerFiller> profiler;
private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector

View File

@@ -0,0 +1,269 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Mon, 9 Jan 2023 13:55:50 +0800
Subject: [PATCH] Hearse: Add config system and rename a class
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/HearseConfig.java b/src/main/java/co/earthme/hearse/HearseConfig.java
index 0a1de52bcdf675b9bfcbf14d39959818a7a0cbbb..73b5e76660b5162a7a0b327ddc7dcc3295b86699 100644
--- a/src/main/java/co/earthme/hearse/HearseConfig.java
+++ b/src/main/java/co/earthme/hearse/HearseConfig.java
@@ -1,5 +1,49 @@
package co.earthme.hearse;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.file.YamlConfiguration;
+import java.io.File;
+import java.io.IOException;
+
public class HearseConfig {
+ private static final YamlConfiguration configEntry = new YamlConfiguration();
+ private static final File CONFIG_FILE = new File("hearse.yml");
+
+ public static void init(){
+ try {
+ configEntry.load(CONFIG_FILE);
+ }catch (IOException ignored){
+ } catch (InvalidConfigurationException e) {
+ e.printStackTrace();
+ }
+ configEntry.options().copyDefaults(true);
+ }
+
+ public static void save(){
+ try {
+ configEntry.save(CONFIG_FILE);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static int getInt(String key,int def){
+ configEntry.addDefault(key,def);
+ return configEntry.getInt(key);
+ }
+
+ public static long getLong(String key,int def){
+ configEntry.addDefault(key,def);
+ return configEntry.getLong(key);
+ }
+
+ public static String getString(String key,String def){
+ configEntry.addDefault(key,def);
+ return configEntry.getString(key);
+ }
+ public static boolean getBoolean(String key,boolean def){
+ configEntry.addDefault(key,def);
+ return configEntry.getBoolean(key);
+ }
}
diff --git a/src/main/java/co/earthme/hearse/server/ServerHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
similarity index 60%
rename from src/main/java/co/earthme/hearse/server/ServerHook.java
rename to src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
index 524a55c3298a079e416c742641af55725a602a2b..8da657836933ae6080e6594ff57dff84155e1820 100644
--- a/src/main/java/co/earthme/hearse/server/ServerHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
@@ -1,36 +1,51 @@
package co.earthme.hearse.server;
+import co.earthme.hearse.HearseConfig;
import co.earthme.hearse.concurrent.WorkerThread;
import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
-import org.apache.logging.log4j.LogManager;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-public class ServerHook {
+public class ServerEntityTickHook {
private static volatile boolean firstTick = false;
private static final AtomicInteger threadId = new AtomicInteger();
- private static final WorkerThreadPoolExecutor worker = new WorkerThreadPoolExecutor(
- Runtime.getRuntime().availableProcessors(),
- Runtime.getRuntime().availableProcessors(),
- 100,
- TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<>(),
- task -> {
- WorkerThread workerThread = new WorkerThread(task,"Hearse-Worker-Thread # "+threadId.getAndIncrement());
- return workerThread;
- }
- );
+ private static WorkerThreadPoolExecutor worker;
+ private static boolean asyncEntityEnabled;
public static void executeAsyncTask(Runnable task){
+ if (!asyncEntityEnabled){
+ throw new IllegalStateException();
+ }
worker.execute(task);
}
+ public static void init(){
+ final boolean asyncEntityEnabled1 = HearseConfig.getBoolean("enable-async-entity",true);
+ final int workerCount = HearseConfig.getInt("async-entity-worker-count",Runtime.getRuntime().availableProcessors());
+ if (asyncEntityEnabled1){
+ worker = new WorkerThreadPoolExecutor(
+ workerCount,
+ workerCount,
+ 100,
+ TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<>(),
+ task -> {
+ return new WorkerThread(task,"Hearse-Worker-Thread # "+threadId.getAndIncrement());
+ }
+ );
+ }
+ asyncEntityEnabled = asyncEntityEnabled1;
+ }
+
public static void executeAsyncTaskWithMainThreadCallback(Runnable task,Runnable callBack){
+ if (!asyncEntityEnabled){
+ throw new IllegalStateException();
+ }
worker.executeWithSubTask(task,callBack);
}
@@ -39,12 +54,15 @@ public class ServerHook {
firstTick = true;
return;
}
+ if (!asyncEntityEnabled){
+ return;
+ }
worker.runAllSubTasks();
}
public static void callAsyncEntityTick(Entity entity, ServerLevel level){
MinecraftServer.getServer().executeMidTickTasks();
- worker.execute(()->{
+ Runnable task = ()->{
entity.activatedPriorityReset = false;
if (!entity.isRemoved()) {
entity.checkDespawn();
@@ -63,6 +81,11 @@ public class ServerHook {
throwable.printStackTrace();
}
}
- });
+ };
+ if (!asyncEntityEnabled){
+ task.run();
+ return;
+ }
+ worker.execute(task);
}
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index e0e169a4403926ff6be004de1bf5ec2079acb440..4a9fc14ba51f8177242c0573d37fd1b4742aa0ae 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1,11 +1,9 @@
package net.minecraft.server;
-import co.earthme.hearse.server.ServerHook;
+import co.earthme.hearse.HearseConfig;
+import co.earthme.hearse.server.ServerEntityTickHook;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
-import co.aikar.timings.Timings;
-import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
-import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -86,7 +84,6 @@ import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
-import net.minecraft.server.level.TicketType;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
import net.minecraft.server.network.ServerConnectionListener;
@@ -110,17 +107,14 @@ import net.minecraft.util.NativeModuleLister;
import net.minecraft.util.ProgressListener;
import net.minecraft.util.RandomSource;
import net.minecraft.util.SignatureValidator;
-import net.minecraft.util.Unit;
import net.minecraft.util.datafix.DataFixers;
import net.minecraft.util.profiling.EmptyProfileResults;
import net.minecraft.util.profiling.ProfileResults;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.util.profiling.ResultField;
-import net.minecraft.util.profiling.SingleTickProfiler;
import net.minecraft.util.profiling.jfr.JvmProfiler;
import net.minecraft.util.profiling.jfr.callback.ProfiledDuration;
import net.minecraft.util.profiling.metrics.profiling.ActiveMetricsRecorder;
-import net.minecraft.util.profiling.metrics.profiling.InactiveMetricsRecorder;
import net.minecraft.util.profiling.metrics.profiling.MetricsRecorder;
import net.minecraft.util.profiling.metrics.profiling.ServerMetricsSamplersProvider;
import net.minecraft.util.profiling.metrics.storage.MetricsPersister;
@@ -184,12 +178,6 @@ import net.minecraft.world.level.levelgen.PatrolSpawner;
import net.minecraft.world.level.levelgen.PhantomSpawner;
import net.minecraft.world.level.levelgen.WorldDimensions;
import net.minecraft.world.level.levelgen.presets.WorldPresets;
-import org.bukkit.Bukkit;
-import org.bukkit.craftbukkit.CraftServer;
-import org.bukkit.craftbukkit.Main;
-import org.bukkit.craftbukkit.util.CraftChatMessage;
-import org.bukkit.craftbukkit.util.LazyPlayerSet;
-import org.bukkit.event.player.AsyncPlayerChatPreviewEvent;
import org.bukkit.event.server.ServerLoadEvent;
// CraftBukkit end
@@ -411,6 +399,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Paper end
Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
this.paperConfigurations = services.paperConfigurations(); // Paper
+ HearseConfig.init();
+ ServerEntityTickHook.init();
}
// CraftBukkit end
@@ -923,6 +913,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper
// Paper start - kill main thread, and kill it hard
+ HearseConfig.save(); //Hearse
shutdownThread = Thread.currentThread();
org.spigotmc.WatchdogThread.doStop(); // Paper
if (!isSameThread()) {
@@ -1408,7 +1399,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
++this.tickCount;
this.tickChildren(shouldKeepTicking);
- ServerHook.callPostTick();
+ ServerEntityTickHook.callPostTick();
if (i - this.lastServerStatus >= 5000000000L) {
this.lastServerStatus = i;
this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount()));
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index bc3cc08cd6effb9328ec74e206fe24bafc4e3d16..68523cb53573baa8ca98177f40acac3745cd625a 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2,7 +2,7 @@ package net.minecraft.server.level;
import co.aikar.timings.TimingHistory;
import co.earthme.hearse.concurrent.WorkerThread;
-import co.earthme.hearse.server.ServerHook;
+import co.earthme.hearse.server.ServerEntityTickHook;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -651,7 +651,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
org.spigotmc.ActivationRange.activateEntities(this); // Spigot
this.entityTickList.forEach((entity) -> {
- ServerHook.callAsyncEntityTick(entity,this);
+ ServerEntityTickHook.callAsyncEntityTick(entity,this);
});
this.tickBlockEntities();
}

View File

@@ -0,0 +1,50 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Mon, 9 Jan 2023 14:55:15 +0800
Subject: [PATCH] Hearse: Run tasks when tick start
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
index 52f0c9dddf29a28cc360fbacb923445e5c3f82a6..783c8ea55095dbabe594a9fe3dc604515bd0c2f1 100644
--- a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
+++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
@@ -4,7 +4,6 @@ import io.papermc.paper.util.TickThread;
public class WorkerThread extends TickThread {
-
public WorkerThread(String name) {
super(name);
this.setDaemon(true);
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
index 8da657836933ae6080e6594ff57dff84155e1820..2c2f752e1ae846c2b24c2d46a13473836c5feac6 100644
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
@@ -49,7 +49,7 @@ public class ServerEntityTickHook {
worker.executeWithSubTask(task,callBack);
}
- public static void callPostTick(){
+ public static void callTickStart(){
if (!firstTick){
firstTick = true;
return;
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 4a9fc14ba51f8177242c0573d37fd1b4742aa0ae..3a7435aabbd759222fbac41ab4ca304bd112a0ac 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1396,10 +1396,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
//isOversleep = false;MinecraftTimings.serverOversleep.stopTiming(); // Purpur
// Paper end
new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper
-
+ ServerEntityTickHook.callTickStart();
++this.tickCount;
this.tickChildren(shouldKeepTicking);
- ServerEntityTickHook.callPostTick();
+
if (i - this.lastServerStatus >= 5000000000L) {
this.lastServerStatus = i;
this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount()));

View File

@@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Mon, 9 Jan 2023 14:57:23 +0800
Subject: [PATCH] Hearse: Adjust some locks
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
index 799cd9d04d156ed87e9b1dfde75ae15280c9eb0d..a1ff442357dfea868c319fd3c10ae28e6fb81956 100644
--- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
+++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
@@ -3,7 +3,9 @@ package net.minecraft.world.level.redstone;
import com.mojang.logging.LogUtils;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Deque;
import java.util.List;
+import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.StampedLock;
import javax.annotation.Nullable;
@@ -18,7 +20,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
private static final Logger LOGGER = LogUtils.getLogger();
private final Level level;
private final int maxChainedNeighborUpdates;
- private final ArrayDeque<CollectingNeighborUpdater.NeighborUpdates> stack = new ArrayDeque<>();
+ private final Deque<NeighborUpdates> stack = new ConcurrentLinkedDeque<>();
private final List<CollectingNeighborUpdater.NeighborUpdates> addedThisLayer = new CopyOnWriteArrayList<>();
private int count = 0;
@@ -28,26 +30,26 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
}
@Override
- public void shapeUpdate(Direction direction, BlockState neighborState, BlockPos pos, BlockPos neighborPos, int flags, int maxUpdateDepth) {
+ public synchronized void shapeUpdate(Direction direction, BlockState neighborState, BlockPos pos, BlockPos neighborPos, int flags, int maxUpdateDepth) {
this.addAndRun(pos, new CollectingNeighborUpdater.ShapeUpdate(direction, neighborState, pos.immutable(), neighborPos.immutable(), flags));
}
@Override
- public void neighborChanged(BlockPos pos, Block sourceBlock, BlockPos sourcePos) {
+ public synchronized void neighborChanged(BlockPos pos, Block sourceBlock, BlockPos sourcePos) {
this.addAndRun(pos, new CollectingNeighborUpdater.SimpleNeighborUpdate(pos, sourceBlock, sourcePos.immutable()));
}
@Override
- public void neighborChanged(BlockState state, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
+ public synchronized void neighborChanged(BlockState state, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
this.addAndRun(pos, new CollectingNeighborUpdater.FullNeighborUpdate(state, pos.immutable(), sourceBlock, sourcePos.immutable(), notify));
}
@Override
- public void updateNeighborsAtExceptFromFacing(BlockPos pos, Block sourceBlock, @Nullable Direction except) {
+ public synchronized void updateNeighborsAtExceptFromFacing(BlockPos pos, Block sourceBlock, @Nullable Direction except) {
this.addAndRun(pos, new CollectingNeighborUpdater.MultiNeighborUpdate(pos.immutable(), sourceBlock, except));
}
- private synchronized void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates entry) {
+ private void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates entry) {
boolean bl = this.count > 0;
boolean bl2 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates;
++this.count;
@@ -64,7 +66,6 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
if (!bl) {
this.runUpdates();
}
-
}
private void runUpdates() {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,671 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Mon, 9 Jan 2023 21:08:52 +0800
Subject: [PATCH] Hearse: Add mcmt's collections and fix some concurrent
problem
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java b/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java
index 277cfd9d1e8fff5d9b5e534b75c3c5162d58b0b7..07247f11b079bfb631010ff06fe353d3dcc0a0f6 100644
--- a/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java
+++ b/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java
@@ -53,7 +53,7 @@ public final class IBlockDataList {
return this.add(getLocationKey(x, y, z), data);
}
- public long add(final int location, final BlockState data) {
+ public synchronized long add(final int location, final BlockState data) {
final long curr = this.map.get((short)location);
if (curr == Long.MAX_VALUE) {
@@ -81,7 +81,7 @@ public final class IBlockDataList {
return this.remove(getLocationKey(x, y, z));
}
- public long remove(final int location) {
+ public synchronized long remove(final int location) {
final long ret = this.map.remove((short)location);
final int index = getIndexFromRaw(ret);
if (ret == Long.MAX_VALUE) {
@@ -101,11 +101,11 @@ public final class IBlockDataList {
return ret;
}
- public int size() {
+ public synchronized int size() {
return this.size;
}
- public long getRaw(final int index) {
+ public synchronized long getRaw(final int index) {
return this.byIndex[index];
}
@@ -117,12 +117,12 @@ public final class IBlockDataList {
return getBlockDataFromRaw(this.getRaw(index));
}
- public void clear() {
+ public synchronized void clear() {
this.size = 0;
this.map.clear();
}
- public LongIterator getRawIterator() {
+ public synchronized LongIterator getRawIterator() {
return this.map.values().iterator();
}
}
diff --git a/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java
index 62a74cbdb7f04b652dddac9e9c6191d5b86c3323..028b23f5c23bbfd83498c3e06a56079ceb0798ad 100644
--- a/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java
+++ b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java
@@ -7,9 +7,9 @@ import io.papermc.paper.util.CoordinateUtils;
import io.papermc.paper.util.IntervalledCounter;
import io.papermc.paper.util.TickThread;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
-import it.unimi.dsi.fastutil.objects.Reference2ObjectLinkedOpenHashMap;
-import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
+import it.unimi.dsi.fastutil.longs.LongSet;
+import it.unimi.dsi.fastutil.longs.LongSets;
+import it.unimi.dsi.fastutil.objects.*;
import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket;
import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket;
import net.minecraft.network.protocol.game.ClientboundSetSimulationDistancePacket;
@@ -24,9 +24,9 @@ import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import java.util.*;
+import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.StampedLock;
public final class PlayerChunkLoader {
@@ -37,11 +37,11 @@ public final class PlayerChunkLoader {
public static final int LOADED_TICKET_LEVEL = 33;
public static int getTickViewDistance(final Player player) {
- return getTickViewDistance(((CraftPlayer) player).getHandle());
+ return getTickViewDistance(((CraftPlayer)player).getHandle());
}
public static int getTickViewDistance(final ServerPlayer player) {
- final ServerLevel level = (ServerLevel) player.level;
+ final ServerLevel level = (ServerLevel)player.level;
final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player);
if (data == null) {
return level.chunkSource.chunkMap.playerChunkManager.getTargetTickViewDistance();
@@ -50,11 +50,11 @@ public final class PlayerChunkLoader {
}
public static int getLoadViewDistance(final Player player) {
- return getLoadViewDistance(((CraftPlayer) player).getHandle());
+ return getLoadViewDistance(((CraftPlayer)player).getHandle());
}
public static int getLoadViewDistance(final ServerPlayer player) {
- final ServerLevel level = (ServerLevel) player.level;
+ final ServerLevel level = (ServerLevel)player.level;
final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player);
if (data == null) {
return level.chunkSource.chunkMap.playerChunkManager.getLoadDistance();
@@ -63,11 +63,11 @@ public final class PlayerChunkLoader {
}
public static int getSendViewDistance(final Player player) {
- return getSendViewDistance(((CraftPlayer) player).getHandle());
+ return getSendViewDistance(((CraftPlayer)player).getHandle());
}
public static int getSendViewDistance(final ServerPlayer player) {
- final ServerLevel level = (ServerLevel) player.level;
+ final ServerLevel level = (ServerLevel)player.level;
final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player);
if (data == null) {
return level.chunkSource.chunkMap.playerChunkManager.getTargetSendDistance();
@@ -76,10 +76,10 @@ public final class PlayerChunkLoader {
}
protected final ChunkMap chunkMap;
- protected final Reference2ObjectLinkedOpenHashMap<ServerPlayer, PlayerLoaderData> playerMap = new Reference2ObjectLinkedOpenHashMap<>(512, 0.7f);
- protected final ReferenceLinkedOpenHashSet<PlayerLoaderData> chunkSendQueue = new ReferenceLinkedOpenHashSet<>(512, 0.7f);
+ protected final Reference2ObjectMap<ServerPlayer, PlayerLoaderData> playerMap = Reference2ObjectMaps.synchronize(new Reference2ObjectLinkedOpenHashMap<>(512, 0.7f));
+ protected final Deque<PlayerLoaderData> chunkSendQueue = new ConcurrentLinkedDeque<>();
- protected final TreeSet<PlayerLoaderData> chunkLoadQueue = new TreeSet<>((final PlayerLoaderData p1, final PlayerLoaderData p2) -> {
+ protected final NavigableSet<PlayerLoaderData> chunkLoadQueue = new ConcurrentSkipListSet<>((final PlayerLoaderData p1, final PlayerLoaderData p2) -> {
if (p1 == p2) {
return 0;
}
@@ -308,8 +308,8 @@ public final class PlayerChunkLoader {
});
}
- protected final LongOpenHashSet isTargetedForPlayerLoad = new LongOpenHashSet();
- protected final LongOpenHashSet chunkTicketTracker = new LongOpenHashSet();
+ protected final LongSet isTargetedForPlayerLoad = LongSets.synchronize(new LongOpenHashSet());
+ protected final LongSet chunkTicketTracker = LongSets.synchronize(new LongOpenHashSet());
public boolean isChunkNearPlayers(final int chunkX, final int chunkZ) {
final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInSendRange = this.broadcastMap.getObjectsInRange(chunkX, chunkZ);
@@ -383,15 +383,15 @@ public final class PlayerChunkLoader {
protected int getMaxChunkLoads() {
double config = GlobalConfiguration.get().chunkLoading.playerMaxConcurrentLoads;
double max = GlobalConfiguration.get().chunkLoading.globalMaxConcurrentLoads;
- return (int) Math.ceil(Math.min(config * MinecraftServer.getServer().getPlayerCount(), max <= 1.0 ? Double.MAX_VALUE : max));
+ return (int)Math.ceil(Math.min(config * MinecraftServer.getServer().getPlayerCount(), max <= 1.0 ? Double.MAX_VALUE : max));
}
protected long getTargetSendPerPlayerAddend() {
- return GlobalConfiguration.get().chunkLoading.targetPlayerChunkSendRate <= 1.0 ? 0L : (long) Math.round(1.0e9 / GlobalConfiguration.get().chunkLoading.targetPlayerChunkSendRate);
+ return GlobalConfiguration.get().chunkLoading.targetPlayerChunkSendRate <= 1.0 ? 0L : (long)Math.round(1.0e9 / GlobalConfiguration.get().chunkLoading.targetPlayerChunkSendRate);
}
protected long getMaxSendAddend() {
- return GlobalConfiguration.get().chunkLoading.globalMaxChunkSendRate <= 1.0 ? 0L : (long) Math.round(1.0e9 / GlobalConfiguration.get().chunkLoading.globalMaxChunkSendRate);
+ return GlobalConfiguration.get().chunkLoading.globalMaxChunkSendRate <= 1.0 ? 0L : (long)Math.round(1.0e9 / GlobalConfiguration.get().chunkLoading.globalMaxChunkSendRate);
}
public void onChunkPlayerTickReady(final int chunkX, final int chunkZ) {
@@ -413,7 +413,7 @@ public final class PlayerChunkLoader {
if (!(raw instanceof ServerPlayer)) {
continue;
}
- this.onChunkSendReady((ServerPlayer) raw, chunkX, chunkZ);
+ this.onChunkSendReady((ServerPlayer)raw, chunkX, chunkZ);
}
}
@@ -481,11 +481,8 @@ public final class PlayerChunkLoader {
return;
}
loaderData.remove();
-
this.chunkLoadQueue.remove(loaderData);
-
this.chunkSendQueue.remove(loaderData);
-
this.chunkSendWaitQueue.remove(loaderData);
synchronized (this.sendingChunkCounts) {
final int count = this.sendingChunkCounts.removeInt(loaderData);
@@ -521,23 +518,21 @@ public final class PlayerChunkLoader {
protected static final AtomicInteger concurrentChunkSends = new AtomicInteger();
protected final Reference2IntOpenHashMap<PlayerLoaderData> sendingChunkCounts = new Reference2IntOpenHashMap<>();
private static long nextChunkSend;
-
private void trySendChunks() {
final long time = System.nanoTime();
if (time < nextChunkSend) {
return;
}
+ PlayerLoaderData data1;
// drain entries from wait queue
- while (!this.chunkSendWaitQueue.isEmpty()) {
- final PlayerLoaderData data = this.chunkSendWaitQueue.first();
-
- if (data.nextChunkSendTarget > time) {
+ while ((data1 = this.chunkSendWaitQueue.pollFirst())!=null) {
+ if (data1.nextChunkSendTarget > time) {
break;
}
this.chunkSendWaitQueue.pollFirst();
- this.chunkSendQueue.add(data);
+ this.chunkSendQueue.add(data1);
}
if (this.chunkSendQueue.isEmpty()) {
@@ -546,11 +541,9 @@ public final class PlayerChunkLoader {
final int maxSends = this.getMaxConcurrentChunkSends();
final long nextPlayerDeadline = this.getTargetSendPerPlayerAddend() + time;
- for (; ; ) {
- if (this.chunkSendQueue.isEmpty()) {
- break;
- }
-
+ final Deque<PlayerLoaderData> tempCopy = new ArrayDeque<>(this.chunkSendQueue);
+ PlayerLoaderData data;
+ while ((data = tempCopy.pollFirst())!=null) {
final int currSends = concurrentChunkSends.get();
if (currSends >= maxSends) {
break;
@@ -559,19 +552,12 @@ public final class PlayerChunkLoader {
if (!concurrentChunkSends.compareAndSet(currSends, currSends + 1)) {
continue;
}
-
// send chunk
-
- PlayerLoaderData data = this.chunkSendQueue.removeFirst();
-
+ this.chunkSendQueue.remove(data);
final ChunkPriorityHolder queuedSend = data.sendQueue.pollFirst();
if (queuedSend == null) {
concurrentChunkSends.getAndDecrement(); // we never sent, so decrease
// stop iterating over players who have nothing to send
- if (this.chunkSendQueue.isEmpty()) {
- // nothing left
- break;
- }
continue;
}
@@ -580,22 +566,24 @@ public final class PlayerChunkLoader {
}
data.nextChunkSendTarget = nextPlayerDeadline;
+ this.chunkSendWaitQueue.add(data);
synchronized (this.sendingChunkCounts) {
this.sendingChunkCounts.addTo(data, 1);
}
+ final PlayerLoaderData finalData = data;
data.sendChunk(queuedSend.chunkX, queuedSend.chunkZ, () -> {
synchronized (this.sendingChunkCounts) {
- final int count = this.sendingChunkCounts.getInt(data);
+ final int count = this.sendingChunkCounts.getInt(finalData);
if (count == 0) {
// disconnected, so we don't need to decrement: it will be decremented for us
return;
}
if (count == 1) {
- this.sendingChunkCounts.removeInt(data);
+ this.sendingChunkCounts.removeInt(finalData);
} else {
- this.sendingChunkCounts.put(data, count - 1);
+ this.sendingChunkCounts.put(finalData, count - 1);
}
}
@@ -611,10 +599,9 @@ public final class PlayerChunkLoader {
protected int concurrentChunkLoads;
// this interval prevents bursting a lot of chunk loads
- protected static final IntervalledCounter TICKET_ADDITION_COUNTER_SHORT = new IntervalledCounter((long) (1.0e6 * 50.0)); // 50ms
+ protected static final IntervalledCounter TICKET_ADDITION_COUNTER_SHORT = new IntervalledCounter((long)(1.0e6 * 50.0)); // 50ms
// this interval ensures the rate is kept between ticks correctly
- protected static final IntervalledCounter TICKET_ADDITION_COUNTER_LONG = new IntervalledCounter((long) (1.0e6 * 1000.0)); // 1000ms
-
+ protected static final IntervalledCounter TICKET_ADDITION_COUNTER_LONG = new IntervalledCounter((long)(1.0e6 * 1000.0)); // 1000ms
private void tryLoadChunks() {
if (this.chunkLoadQueue.isEmpty()) {
return;
@@ -623,16 +610,12 @@ public final class PlayerChunkLoader {
final int maxLoads = this.getMaxChunkLoads();
final long time = System.nanoTime();
boolean updatedCounters = false;
- for (; ; ) {
- PlayerLoaderData data = this.chunkLoadQueue.pollFirst();
-
+ PlayerLoaderData data;
+ while ((data = this.chunkLoadQueue.pollFirst())!=null) {
data.lastChunkLoad = time;
final ChunkPriorityHolder queuedLoad = data.loadQueue.peekFirst();
if (queuedLoad == null) {
- if (this.chunkLoadQueue.isEmpty()) {
- break;
- }
continue;
}
@@ -648,6 +631,7 @@ public final class PlayerChunkLoader {
// already loaded!
data.loadQueue.pollFirst(); // already loaded so we just skip
this.chunkLoadQueue.add(data);
+
// ensure the chunk is queued to send
this.onChunkSendReady(queuedLoad.chunkX, queuedLoad.chunkZ);
continue;
@@ -768,7 +752,7 @@ public final class PlayerChunkLoader {
protected static final double PRIORITISED_DISTANCE = 12.0 * 16.0;
// Player max sprint speed is approximately 8m/s
- protected static final double LOOK_PRIORITY_SPEED_THRESHOLD = (10.0 / 20.0) * (10.0 / 20.0);
+ protected static final double LOOK_PRIORITY_SPEED_THRESHOLD = (10.0/20.0) * (10.0/20.0);
protected static final double LOOK_PRIORITY_YAW_DELTA_RECALC_THRESHOLD = 3.0f;
protected double lastLocX = Double.NEGATIVE_INFINITY;
@@ -790,11 +774,11 @@ public final class PlayerChunkLoader {
// warning: modifications of this field must be aware that the loadQueue inside PlayerChunkLoader uses this field
// in a comparator!
- protected final ArrayDeque<ChunkPriorityHolder> loadQueue = new ArrayDeque<>();
- protected final LongOpenHashSet sentChunks = new LongOpenHashSet();
- protected final LongOpenHashSet chunksToBeSent = new LongOpenHashSet();
+ protected final Deque<ChunkPriorityHolder> loadQueue = new ConcurrentLinkedDeque<>();
+ protected final LongSet sentChunks = LongSets.synchronize(new LongOpenHashSet());
+ protected final LongSet chunksToBeSent = LongSets.synchronize(new LongOpenHashSet());
- protected final TreeSet<ChunkPriorityHolder> sendQueue = new TreeSet<>((final ChunkPriorityHolder p1, final ChunkPriorityHolder p2) -> {
+ protected final NavigableSet<ChunkPriorityHolder> sendQueue = new ConcurrentSkipListSet<>((final ChunkPriorityHolder p1, final ChunkPriorityHolder p2) -> {
final int distanceCompare = Integer.compare(p1.manhattanDistanceToPlayer, p2.manhattanDistanceToPlayer);
if (distanceCompare != 0) {
return distanceCompare;
@@ -815,9 +799,9 @@ public final class PlayerChunkLoader {
protected long nextChunkSendTarget;
// this interval prevents bursting a lot of chunk loads
- protected final IntervalledCounter ticketAdditionCounterShort = new IntervalledCounter((long) (1.0e6 * 50.0)); // 50ms
+ protected final IntervalledCounter ticketAdditionCounterShort = new IntervalledCounter((long)(1.0e6 * 50.0)); // 50ms
// this ensures the rate is kept between ticks correctly
- protected final IntervalledCounter ticketAdditionCounterLong = new IntervalledCounter((long) (1.0e6 * 1000.0)); // 1000ms
+ protected final IntervalledCounter ticketAdditionCounterLong = new IntervalledCounter((long)(1.0e6 * 1000.0)); // 1000ms
public long lastChunkLoad;
@@ -914,14 +898,14 @@ public final class PlayerChunkLoader {
// b = ((p3z - p1z)(targetX - p3x) + (p1x - p3x)(targetZ - p3z)) / d
// c = 1.0 - a - b
- final double d = (p2z - p3z) * (p1x - p3x) + (p3x - p2x) * (p1z - p3z);
- final double a = ((p2z - p3z) * (targetX - p3x) + (p3x - p2x) * (targetZ - p3z)) / d;
+ final double d = (p2z - p3z)*(p1x - p3x) + (p3x - p2x)*(p1z - p3z);
+ final double a = ((p2z - p3z)*(targetX - p3x) + (p3x - p2x)*(targetZ - p3z)) / d;
if (a < 0.0 || a > 1.0) {
return false;
}
- final double b = ((p3z - p1z) * (targetX - p3x) + (p1x - p3x) * (targetZ - p3z)) / d;
+ final double b = ((p3z - p1z)*(targetX - p3x) + (p1x - p3x)*(targetZ - p3z)) / d;
if (b < 0.0 || b > 1.0) {
return false;
}
@@ -1024,15 +1008,15 @@ public final class PlayerChunkLoader {
final double p1z = posZ;
// to the left of the looking direction
- final double p2x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw + (double) (FOV / 2.0))) // calculate rotated vector
+ final double p2x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw + (double)(FOV / 2.0))) // calculate rotated vector
+ p1x; // offset vector
- final double p2z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw + (double) (FOV / 2.0))) // calculate rotated vector
+ final double p2z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw + (double)(FOV / 2.0))) // calculate rotated vector
+ p1z; // offset vector
// to the right of the looking direction
- final double p3x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw - (double) (FOV / 2.0))) // calculate rotated vector
+ final double p3x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw - (double)(FOV / 2.0))) // calculate rotated vector
+ p1x; // offset vector
- final double p3z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw - (double) (FOV / 2.0))) // calculate rotated vector
+ final double p3z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw - (double)(FOV / 2.0))) // calculate rotated vector
+ p1z; // offset vector
// now that we have all of our points, we can recalculate the load queue
@@ -1070,7 +1054,7 @@ public final class PlayerChunkLoader {
p1x, p1z, p2x, p2z, p3x, p3z,
// center of chunk
- (double) ((chunkX << 4) | 8), (double) ((chunkZ << 4) | 8)
+ (double)((chunkX << 4) | 8), (double)((chunkZ << 4) | 8)
);
final int manhattanDistance = Math.abs(dx) + Math.abs(dz);
@@ -1085,9 +1069,9 @@ public final class PlayerChunkLoader {
if (prioritised) {
// we don't prioritise these chunks above others because we also want to make sure some chunks
// will be loaded if the player changes direction
- priority = (double) manhattanDistance / 6.0;
+ priority = (double)manhattanDistance / 6.0;
} else {
- priority = (double) manhattanDistance;
+ priority = (double)manhattanDistance;
}
}
diff --git a/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java b/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java
index 470402573bc31106d5a63e415b958fb7f9c36aa9..762f09c8f374fbccc9f5be985401ad334e1655a0 100644
--- a/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java
+++ b/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java
@@ -94,24 +94,24 @@ public final class Delayed26WayDistancePropagator3D {
protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate);
+ queue.queuedLevels.add(level);
this.levelIncreaseWorkQueueBitset |= (1L << level);
}
protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[index];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate);
+ queue.queuedLevels.add(level);
this.levelIncreaseWorkQueueBitset |= (1L << index);
}
protected final void addToRemoveWorkQueue(final long coordinate, final byte level) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate);
+ queue.queuedLevels.add(level);
this.levelRemoveWorkQueueBitset |= (1L << level);
}
@@ -164,8 +164,8 @@ public final class Delayed26WayDistancePropagator3D {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst();
+ byte level = queue.queuedLevels.removeFirst();
final boolean neighbourCheck = level < 0;
@@ -233,8 +233,8 @@ public final class Delayed26WayDistancePropagator3D {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- final byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst();
+ final byte level = queue.queuedLevels.removeFirst();
final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level);
if (currentLevel == 0) {
diff --git a/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java b/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java
index 808d1449ac44ae86a650932365081fbaf178d141..8c5a51b5992eccf3627f326e164288b5f6bbcff6 100644
--- a/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java
+++ b/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java
@@ -1,12 +1,13 @@
package io.papermc.paper.util.misc;
+import io.papermc.paper.util.MCUtil;
import it.unimi.dsi.fastutil.HashCommon;
-import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue;
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
-import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
-import io.papermc.paper.util.MCUtil;
+
+import java.util.Deque;
+import java.util.concurrent.ConcurrentLinkedDeque;
public final class Delayed8WayDistancePropagator2D {
@@ -356,24 +357,24 @@ public final class Delayed8WayDistancePropagator2D {
protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) {
final WorkQueue queue = this.levelIncreaseWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate);
+ queue.queuedLevels.add(level);
this.levelIncreaseWorkQueueBitset |= (1L << level);
}
protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) {
final WorkQueue queue = this.levelIncreaseWorkQueues[index];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate);
+ queue.queuedLevels.add(level);
this.levelIncreaseWorkQueueBitset |= (1L << index);
}
protected final void addToRemoveWorkQueue(final long coordinate, final byte level) {
final WorkQueue queue = this.levelRemoveWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate);
+ queue.queuedLevels.add(level);
this.levelRemoveWorkQueueBitset |= (1L << level);
}
@@ -426,8 +427,8 @@ public final class Delayed8WayDistancePropagator2D {
final WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst();
+ byte level = queue.queuedLevels.removeFirst();
final boolean neighbourCheck = level < 0;
@@ -492,8 +493,8 @@ public final class Delayed8WayDistancePropagator2D {
final WorkQueue queue = this.levelRemoveWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- final byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst();
+ final byte level = queue.queuedLevels.removeFirst();
final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level);
if (currentLevel == 0) {
@@ -678,41 +679,8 @@ public final class Delayed8WayDistancePropagator2D {
}
protected static final class WorkQueue {
-
- public final NoResizeLongArrayFIFODeque queuedCoordinates = new NoResizeLongArrayFIFODeque();
- public final NoResizeByteArrayFIFODeque queuedLevels = new NoResizeByteArrayFIFODeque();
-
- }
-
- protected static final class NoResizeLongArrayFIFODeque extends LongArrayFIFOQueue {
-
- /**
- * Assumes non-empty. If empty, undefined behaviour.
- */
- public long removeFirstLong() {
- // copied from superclass
- long t = this.array[this.start];
- if (++this.start == this.length) {
- this.start = 0;
- }
-
- return t;
- }
+ public final Deque<Long> queuedCoordinates = new ConcurrentLinkedDeque<>();
+ public final Deque<Byte> queuedLevels = new ConcurrentLinkedDeque<>();
}
- protected static final class NoResizeByteArrayFIFODeque extends ByteArrayFIFOQueue {
-
- /**
- * Assumes non-empty. If empty, undefined behaviour.
- */
- public byte removeFirstByte() {
- // copied from superclass
- byte t = this.array[this.start];
- if (++this.start == this.length) {
- this.start = 0;
- }
-
- return t;
- }
- }
}
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
index e642b4a83687d03e55feb340452d608c53ae7cce..4beaa69da4001fc2723e9628d64bd3de728d7213 100644
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
@@ -5,6 +5,7 @@ import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.shorts.ShortArraySet;
import it.unimi.dsi.fastutil.shorts.ShortSet;
import it.unimi.dsi.fastutil.shorts.ShortSets;
+import net.himeki.mcmtfabric.parallelised.fastutil.ConcurrentShortHashSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.Packet;
@@ -222,7 +223,7 @@ public class ChunkHolder {
if (i < 0 || i >= this.changedBlocksPerSection.length) return; // CraftBukkit - SPIGOT-6086, SPIGOT-6296
if (this.changedBlocksPerSection[i] == null) {
this.hasChangedSections = true; this.addToBroadcastMap(); // Paper - optimise chunk tick iteration
- this.changedBlocksPerSection[i] = ShortSets.synchronize(new ShortArraySet());
+ this.changedBlocksPerSection[i] = new ConcurrentShortHashSet();
}
this.changedBlocksPerSection[i].add(SectionPos.sectionRelativePos(pos));
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 81697ea6d00967852556c3bb741317db030c24db..85c03dc7c1e714fab281374a177cd4c54e97d939 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -788,7 +788,7 @@ public class ServerChunkCache extends ChunkSource {
//gameprofilerfiller.popPush("broadcast"); // Purpur
//this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing // Purpur
if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) {
- ObjectSet<ChunkHolder> copy = new ObjectArraySet<>(this.chunkMap.needsChangeBroadcasting);
+ List<ChunkHolder> copy = new ArrayList<>(this.chunkMap.needsChangeBroadcasting);
this.chunkMap.needsChangeBroadcasting.clear();
for (ChunkHolder holder : copy) {
holder.broadcastChanges(holder.getFullChunkNowUnchecked()); // LevelChunks are NEVER unloaded
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
index 9f138bc471b5c2a4fa813ff943dbe34018b8df74..5c8a90f8536c9291df5891d8c75de963b75ec4bd 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
@@ -7,6 +7,7 @@ import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
+import it.unimi.dsi.fastutil.shorts.Short2ObjectMaps;
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
import java.util.List;
import java.util.Map;
@@ -25,8 +26,9 @@ import org.slf4j.Logger;
public class PoiSection {
private static final Logger LOGGER = LogUtils.getLogger();
- private final Short2ObjectMap<PoiRecord> records = new Short2ObjectOpenHashMap<>();
- private final Map<Holder<PoiType>, Set<PoiRecord>> byType = Maps.newHashMap(); public final Map<Holder<PoiType>, Set<PoiRecord>> getData() { return this.byType; } // Paper - public accessor
+ private final Short2ObjectMap<PoiRecord> records = Short2ObjectMaps.synchronize(new Short2ObjectOpenHashMap<>());
+ private final Map<Holder<PoiType>, Set<PoiRecord>> byType = Maps.newConcurrentMap();
+ public final Map<Holder<PoiType>, Set<PoiRecord>> getData() { return this.byType; } // Paper - public accessor
private final Runnable setDirty;
private boolean isValid;
public final Optional<PoiSection> noAllocateOptional = Optional.of(this); // Paper - rewrite chunk system
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 8450a22b0fc6e8dc5cad0f61ac52a82b3cd3791e..c55f98fb2a6aade8e0a6f60248f4e29f66f0c193 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -248,7 +248,9 @@ public final class ItemStack {
}
private void updateEmptyCacheFlag() {
- if (this.emptyCacheFlag && this == ItemStack.EMPTY) throw new AssertionError("TRAP"); // CraftBukkit
+ if (this.emptyCacheFlag && this == ItemStack.EMPTY){
+ return;
+ }//throw new AssertionError("TRAP"); // CraftBukkit
this.emptyCacheFlag = false;
this.emptyCacheFlag = this.isEmpty();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Tue, 10 Jan 2023 12:50:27 +0800
Subject: [PATCH] Hearse: Fix some concurrent problems in Explosion
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 5ef58831a857fd8aa4ac30147762dc17d773a53e..2a8590d46bab64fe27e8dadf80f91ab0662a4352 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -65,6 +65,8 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import javax.annotation.Nullable;
+
+import it.unimi.dsi.fastutil.objects.ObjectList;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.Bootstrap;
import net.minecraft.util.Mth;
@@ -793,7 +795,7 @@ public class Util {
return objectArrayList;
}
- public static <T> void shuffle(ObjectArrayList<T> list, RandomSource random) {
+ public static <T> void shuffle(ObjectList<T> list, RandomSource random) {
int i = list.size();
for(int j = i; j > 1; --j) {
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index c0d39afe5b80159ed9aaca4ddd4763d707882f2e..2f53f8f2695231179ff16bb014cd990e94f9ec79 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -4,12 +4,15 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import it.unimi.dsi.fastutil.objects.ObjectList;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
+
+import it.unimi.dsi.fastutil.objects.ObjectLists;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
@@ -63,7 +66,7 @@ public class Explosion {
private final float radius;
private final DamageSource damageSource;
private final ExplosionDamageCalculator damageCalculator;
- private final ObjectArrayList<BlockPos> toBlow;
+ private final ObjectList<BlockPos> toBlow;
private final Map<Player, Vec3> hitPlayers;
public boolean wasCanceled = false; // CraftBukkit - add field
@@ -81,9 +84,9 @@ public class Explosion {
}
public Explosion(Level world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Explosion.BlockInteraction destructionType) {
- this.random = RandomSource.create();
- this.toBlow = new ObjectArrayList();
- this.hitPlayers = Maps.newHashMap();
+ this.random = RandomSource.createThreadSafe();
+ this.toBlow = ObjectLists.synchronize(new ObjectArrayList<>());
+ this.hitPlayers = Maps.newConcurrentMap();
this.level = world;
this.source = entity;
this.radius = (float) Math.max(power, 0.0); // CraftBukkit - clamp bad values
@@ -396,14 +399,10 @@ public class Explosion {
}
if (this.fire) {
- ObjectListIterator objectlistiterator1 = this.toBlow.iterator();
-
- while (objectlistiterator1.hasNext()) {
- BlockPos blockposition2 = (BlockPos) objectlistiterator1.next();
-
+ for (BlockPos blockposition2 : this.toBlow) {
if (this.random.nextInt(3) == 0 && this.level.getBlockState(blockposition2).isAir() && this.level.getBlockState(blockposition2.below()).isSolidRender(this.level, blockposition2.below())) {
// CraftBukkit start - Ignition by explosion
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level, blockposition2.getX(), blockposition2.getY(), blockposition2.getZ(), this).isCancelled()) {
+ if (!CraftEventFactory.callBlockIgniteEvent(this.level, blockposition2.getX(), blockposition2.getY(), blockposition2.getZ(), this).isCancelled()) {
this.level.setBlockAndUpdate(blockposition2, BaseFireBlock.getState(this.level, blockposition2));
}
// CraftBukkit end

View File

@@ -0,0 +1,187 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Tue, 10 Jan 2023 16:42:02 +0800
Subject: [PATCH] Hearse: Fix some problems and update workerpool
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
index 783c8ea55095dbabe594a9fe3dc604515bd0c2f1..421d4926ac674b5eb12d9613ceb6d20185ea557d 100644
--- a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
+++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java
@@ -6,14 +6,10 @@ public class WorkerThread extends TickThread {
public WorkerThread(String name) {
super(name);
- this.setDaemon(true);
- this.setPriority(Thread.NORM_PRIORITY - 2);
}
public WorkerThread(Runnable run, String name) {
super(run, name);
- this.setDaemon(true);
- this.setPriority(Thread.NORM_PRIORITY - 2);
}
public static boolean isWorker(){
diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java
index 8899c02a2242b51097a03c7e3ca03b8768c60117..7e010bf23c9fc26284212a4388172f5d7d5a4b99 100644
--- a/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java
+++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java
@@ -17,6 +17,14 @@ public class WorkerThreadPoolExecutor extends ThreadPoolExecutor {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, workerThreadFactory::getNewThread, handler);
}
+ public int getCurrentNotProcessingTasks(){
+ return this.getQueue().size();
+ }
+
+ public void clearAllTasks(){
+ this.getQueue().clear();
+ }
+
public void executeWithSubTask(Runnable mainTask,Runnable subTask){
final TaskEntry wrapped = new TaskEntry(subTask,mainTask);
this.taskEntries.offer(wrapped);
diff --git a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e3ae10fcc54b80ff4ec433f136d15d3b9fa4fe4
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
@@ -0,0 +1,22 @@
+package co.earthme.hearse.concurrent.threadfactory;
+
+import co.earthme.hearse.concurrent.WorkerThread;
+import co.earthme.hearse.concurrent.WorkerThreadFactory;
+import net.minecraft.server.MinecraftServer;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class DefaultWorkerFactory implements WorkerThreadFactory {
+ private static final AtomicInteger poolId = new AtomicInteger();
+ private final AtomicInteger threadId = new AtomicInteger();
+
+ @Override
+ public WorkerThread getNewThread(Runnable task) {
+ final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.getAndIncrement()+"-worker-"+threadId.getAndIncrement());
+ if (workerThread.isDaemon()){
+ workerThread.setDaemon(false);
+ }
+ workerThread.setPriority(Thread.NORM_PRIORITY - 2);
+ workerThread.setContextClassLoader(MinecraftServer.class.getClassLoader());
+ return workerThread;
+ }
+}
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
index 2c2f752e1ae846c2b24c2d46a13473836c5feac6..8605d867bea87095dcf43e1c1ebedbb9180c4480 100644
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
@@ -2,7 +2,9 @@ package co.earthme.hearse.server;
import co.earthme.hearse.HearseConfig;
import co.earthme.hearse.concurrent.WorkerThread;
+import co.earthme.hearse.concurrent.WorkerThreadFactory;
import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
+import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
@@ -13,6 +15,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class ServerEntityTickHook {
private static volatile boolean firstTick = false;
+ private static final WorkerThreadFactory defFactory = new DefaultWorkerFactory();
private static final AtomicInteger threadId = new AtomicInteger();
private static WorkerThreadPoolExecutor worker;
private static boolean asyncEntityEnabled;
@@ -24,19 +27,25 @@ public class ServerEntityTickHook {
worker.execute(task);
}
+ public static void onServerStop() throws InterruptedException {
+ if (!asyncEntityEnabled){
+ return;
+ }
+ worker.shutdown();
+ while (!worker.awaitTermination(100,TimeUnit.MILLISECONDS));
+ }
+
public static void init(){
- final boolean asyncEntityEnabled1 = HearseConfig.getBoolean("enable-async-entity",true);
+ boolean asyncEntityEnabled1 = HearseConfig.getBoolean("enable-async-entity",true);
final int workerCount = HearseConfig.getInt("async-entity-worker-count",Runtime.getRuntime().availableProcessors());
if (asyncEntityEnabled1){
worker = new WorkerThreadPoolExecutor(
workerCount,
workerCount,
- 100,
+ 0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
- task -> {
- return new WorkerThread(task,"Hearse-Worker-Thread # "+threadId.getAndIncrement());
- }
+ defFactory
);
}
asyncEntityEnabled = asyncEntityEnabled1;
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 2a8590d46bab64fe27e8dadf80f91ab0662a4352..5ef58831a857fd8aa4ac30147762dc17d773a53e 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -65,8 +65,6 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import javax.annotation.Nullable;
-
-import it.unimi.dsi.fastutil.objects.ObjectList;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.Bootstrap;
import net.minecraft.util.Mth;
@@ -795,7 +793,7 @@ public class Util {
return objectArrayList;
}
- public static <T> void shuffle(ObjectList<T> list, RandomSource random) {
+ public static <T> void shuffle(ObjectArrayList<T> list, RandomSource random) {
int i = list.size();
for(int j = i; j > 1; --j) {
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 3a7435aabbd759222fbac41ab4ca304bd112a0ac..9c4811a9936f819e201b93e13519abf10d02ac8e 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -914,6 +914,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper
// Paper start - kill main thread, and kill it hard
HearseConfig.save(); //Hearse
+ try {
+ ServerEntityTickHook.onServerStop(); //Hearse
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
shutdownThread = Thread.currentThread();
org.spigotmc.WatchdogThread.doStop(); // Paper
if (!isSameThread()) {
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index 2f53f8f2695231179ff16bb014cd990e94f9ec79..a4e031682329e127a61a9fa03a7383cd3e58d503 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -66,7 +66,7 @@ public class Explosion {
private final float radius;
private final DamageSource damageSource;
private final ExplosionDamageCalculator damageCalculator;
- private final ObjectList<BlockPos> toBlow;
+ private final ObjectArrayList<BlockPos> toBlow;
private final Map<Player, Vec3> hitPlayers;
public boolean wasCanceled = false; // CraftBukkit - add field
@@ -85,7 +85,7 @@ public class Explosion {
public Explosion(Level world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Explosion.BlockInteraction destructionType) {
this.random = RandomSource.createThreadSafe();
- this.toBlow = ObjectLists.synchronize(new ObjectArrayList<>());
+ this.toBlow = new ObjectArrayList<>();
this.hitPlayers = Maps.newConcurrentMap();
this.level = world;
this.source = entity;

View File

@@ -0,0 +1,113 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Tue, 10 Jan 2023 18:52:00 +0800
Subject: [PATCH] Hearse: Change some config key name
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
index 8605d867bea87095dcf43e1c1ebedbb9180c4480..cf7ee6fda90fa0f6827dc2d1c584151e3b99fb38 100644
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
@@ -36,8 +36,8 @@ public class ServerEntityTickHook {
}
public static void init(){
- boolean asyncEntityEnabled1 = HearseConfig.getBoolean("enable-async-entity",true);
- final int workerCount = HearseConfig.getInt("async-entity-worker-count",Runtime.getRuntime().availableProcessors());
+ boolean asyncEntityEnabled1 = HearseConfig.getBoolean("optimizations.enable-async-entity",true);
+ final int workerCount = HearseConfig.getInt("workers.async-entity-worker-count",Runtime.getRuntime().availableProcessors());
if (asyncEntityEnabled1){
worker = new WorkerThreadPoolExecutor(
workerCount,
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 68523cb53573baa8ca98177f40acac3745cd625a..ac92d1b36590bcc491d56a1eb442477c8f6e2d11 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1126,13 +1126,10 @@ public class ServerLevel extends Level implements WorldGenLevel {
} else { entity.inactiveTick(); } // Paper - EAR 2
//this.getProfiler().pop(); // Purpur
//} finally { timer.stopTiming(); } // Paper - timings // Purpur
- Iterator iterator = entity.getPassengers().iterator();
- while (iterator.hasNext()) {
- Entity entity1 = (Entity) iterator.next();
-
- this.tickPassenger(entity, entity1);
- }
+ for (Entity entity1 : entity.getPassengers()) {
+ this.tickPassenger(entity, entity1);
+ }
// } finally { timer.stopTiming(); } // Paper - timings - move up
// Paper start - log detailed entity tick information
} finally {
@@ -1171,11 +1168,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
// Paper end - EAR 2
//gameprofilerfiller.pop(); // Purpur
- Iterator iterator = passenger.getPassengers().iterator();
-
- while (iterator.hasNext()) {
- Entity entity2 = (Entity) iterator.next();
+ for (Entity entity2 : passenger.getPassengers()) {
this.tickPassenger(passenger, entity2);
}
diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
index dca7c7f83043452b5fef3c1d24a99f08dfaf242a..2a14b665437336aa32ca14fb2137d5bb400e2e42 100644
--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
@@ -1,28 +1,25 @@
package net.minecraft.world.level.entity;
-import java.util.*;
-import java.util.function.Consumer;
-
import com.google.common.collect.Lists;
-import it.unimi.dsi.fastutil.objects.ObjectArraySet;
-import it.unimi.dsi.fastutil.objects.ObjectSets;
import net.minecraft.world.entity.Entity;
+import java.util.List;
+import java.util.function.Consumer;
public class EntityTickList {
public final List<Entity> entities = Lists.newCopyOnWriteArrayList();
public void add(Entity entity) {
io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist addition"); // Paper
- this.entities.add(entity); // Paper - replace with better logic, do not delay removals/additions
+ this.entities.add(entity);
}
public void remove(Entity entity) {
io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist removal"); // Paper
- this.entities.remove(entity); // Paper - replace with better logic, do not delay removals/additions
+ this.entities.remove(entity);
}
public boolean contains(Entity entity) {
- return this.entities.contains(entity); // Paper - replace with better logic, do not delay removals/additions
+ return this.entities.contains(entity);
}
public void forEach(Consumer<Entity> action) {
@@ -30,6 +27,5 @@ public class EntityTickList {
for (Entity entity : this.entities) {
action.accept(entity);
}
- // Paper end - replace with better logic, do not delay removals/additions
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 96cde1f86ca073e7e9e5799bcb12a10adf9230b2..c0ce5a75923e9482d3bd76fbcf730e6c6cd1bbda 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1,5 +1,6 @@
package org.bukkit.craftbukkit;
+import co.earthme.hearse.HearseConfig;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;

View File

@@ -0,0 +1,302 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Wed, 11 Jan 2023 10:10:12 +0800
Subject: [PATCH] Hearse: Add worker command
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/Hearse.java b/src/main/java/co/earthme/hearse/Hearse.java
new file mode 100644
index 0000000000000000000000000000000000000000..79116449c221e0748e938f40366af03f93a4ab9f
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/Hearse.java
@@ -0,0 +1,25 @@
+package co.earthme.hearse;
+
+import co.earthme.hearse.commands.WorkerCommand;
+import co.earthme.hearse.server.ServerEntityTickHook;
+import co.earthme.hearse.workers.WorkerThreadPoolManager;
+import net.minecraft.server.MinecraftServer;
+
+public class Hearse {
+ private static final WorkerThreadPoolManager workerManager = new WorkerThreadPoolManager();
+
+ public static void initAll(){
+ HearseConfig.init();
+ ServerEntityTickHook.init();
+ MinecraftServer.getServer().server.getCommandMap().register("workers","hearse",new WorkerCommand());
+ }
+
+ public static void onServerStop(){
+ HearseConfig.save();
+ workerManager.shutdownAllNow();
+ }
+
+ public static WorkerThreadPoolManager getWorkerManager() {
+ return workerManager;
+ }
+}
diff --git a/src/main/java/co/earthme/hearse/commands/WorkerCommand.java b/src/main/java/co/earthme/hearse/commands/WorkerCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bf8e0bdfed9a30a302c6369a727e8bb394b4670
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/commands/WorkerCommand.java
@@ -0,0 +1,72 @@
+package co.earthme.hearse.commands;
+
+import co.earthme.hearse.Hearse;
+import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.jetbrains.annotations.NotNull;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class WorkerCommand extends Command {
+ public WorkerCommand() {
+ super("workers");
+ this.setPermission("hearse.commands.workers");
+ this.setDescription("You can see or edit the server workers by using this command");
+ this.setUsage("/workers <status,setThreadCount,forceStop> <workername>");
+ }
+
+ @Override
+ public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
+ final List<String> ret = new ArrayList<>();
+ if (args.length == 1){
+ ret.add("status");
+ ret.add("setThreadCount");
+ ret.add("forceStop");
+ }
+ if (args.length == 2){
+ for (Map.Entry<String, WorkerThreadPoolExecutor> entry : Hearse.getWorkerManager().getManagedWorkers().entrySet()){
+ ret.add(entry.getKey());
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
+ if (args.length >= 2){
+ final String action = args[0];
+ final String workerName = args[1];
+ final WorkerThreadPoolExecutor searchedWorker = Hearse.getWorkerManager().getTargetWorker(workerName);
+ if (searchedWorker == null){
+ sender.sendMessage(ChatColor.RED+"Target worker not found!");
+ return true;
+ }
+ switch (action){
+ case "status":
+ sender.sendMessage(ChatColor.GREEN+"Worker: "+workerName+" Status:"+ searchedWorker);
+ break;
+ case "setThreadCount":
+ if (args.length == 3){
+ try {
+ searchedWorker.setCorePoolSize(Integer.parseInt(args[2]));
+ sender.sendMessage(ChatColor.GREEN+"Finished!");
+ }catch (NumberFormatException e){
+ sender.sendMessage(ChatColor.RED+"Please supply a integer!");
+ }
+ }else{
+ sender.sendMessage(ChatColor.RED+"Please supply a integer!");
+ }
+ break;
+ case "forceStop":
+ searchedWorker.shutdownNow();
+ sender.sendMessage(ChatColor.YELLOW+"Worker "+workerName+" has been stopped!");
+ break;
+ }
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
index cf7ee6fda90fa0f6827dc2d1c584151e3b99fb38..18c1f6ee4d4fc422fb2aa41483ce145d34fa39b1 100644
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
@@ -1,14 +1,13 @@
package co.earthme.hearse.server;
+import co.earthme.hearse.Hearse;
import co.earthme.hearse.HearseConfig;
-import co.earthme.hearse.concurrent.WorkerThread;
import co.earthme.hearse.concurrent.WorkerThreadFactory;
import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
-
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -27,14 +26,6 @@ public class ServerEntityTickHook {
worker.execute(task);
}
- public static void onServerStop() throws InterruptedException {
- if (!asyncEntityEnabled){
- return;
- }
- worker.shutdown();
- while (!worker.awaitTermination(100,TimeUnit.MILLISECONDS));
- }
-
public static void init(){
boolean asyncEntityEnabled1 = HearseConfig.getBoolean("optimizations.enable-async-entity",true);
final int workerCount = HearseConfig.getInt("workers.async-entity-worker-count",Runtime.getRuntime().availableProcessors());
@@ -47,6 +38,7 @@ public class ServerEntityTickHook {
new LinkedBlockingQueue<>(),
defFactory
);
+ Hearse.getWorkerManager().addWorker("entity",worker);
}
asyncEntityEnabled = asyncEntityEnabled1;
}
diff --git a/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java b/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..90dd97491c0313bee031b81aa43fe6df3dda5b4f
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java
@@ -0,0 +1,84 @@
+package co.earthme.hearse.workers;
+
+import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
+import com.google.common.collect.Maps;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class WorkerThreadPoolManager {
+ private final Map<String,WorkerThreadPoolExecutor> managedWorkers = Maps.newConcurrentMap();
+
+ public void addWorker(String bound,WorkerThreadPoolExecutor worker){
+ this.managedWorkers.put(bound,worker);
+ }
+
+ public void shutdownAll() throws InterruptedException {
+ for (WorkerThreadPoolExecutor worker : this.managedWorkers.values()){
+ worker.shutdown();
+ while (worker.awaitTermination(100, TimeUnit.MILLISECONDS)) {}
+ }
+ }
+
+ public Map<String, WorkerThreadPoolExecutor> getManagedWorkers() {
+ return Maps.newHashMap(this.managedWorkers);
+ }
+
+ public WorkerThreadPoolExecutor getTargetWorker(String bound){
+ return this.managedWorkers.get(bound);
+ }
+
+ public Map<String,List<Runnable>> shutdownAllNow(){
+ final Map<String,List<Runnable>> ret = Maps.newHashMap();
+ for (Map.Entry<String,WorkerThreadPoolExecutor> entry : this.managedWorkers.entrySet()){
+ final String workerName = entry.getKey();
+ final WorkerThreadPoolExecutor worker = entry.getValue();
+ try {
+ final List<Runnable> taskNotRunned = worker.shutdownNow();
+ while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){
+
+ }
+ ret.put(workerName,taskNotRunned);
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ }
+ return ret;
+ }
+
+ public Map<String,List<Runnable>> shutdownAllNow(long timeOutCount){
+ final Map<String,List<Runnable>> ret = Maps.newHashMap();
+ for (Map.Entry<String,WorkerThreadPoolExecutor> entry : this.managedWorkers.entrySet()){
+ final String workerName = entry.getKey();
+ final WorkerThreadPoolExecutor worker = entry.getValue();
+ try {
+ long timeCounter = timeOutCount;
+ final List<Runnable> taskNotRunned = worker.shutdownNow();
+ while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){
+ if (timeCounter == 0){
+ break;
+ }
+ timeCounter--;
+ }
+ ret.put(workerName,taskNotRunned);
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ }
+ return ret;
+ }
+
+ public void shutdownAll(long singleWorkerAwaitTimeOutCount) throws InterruptedException {
+ long counter = singleWorkerAwaitTimeOutCount;
+ for (WorkerThreadPoolExecutor worker : this.managedWorkers.values()){
+ worker.shutdown();
+ while (worker.awaitTermination(1, TimeUnit.MILLISECONDS)) {
+ if (counter == 0){
+ break;
+ }
+ counter--;
+ }
+ counter = singleWorkerAwaitTimeOutCount;
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 9c4811a9936f819e201b93e13519abf10d02ac8e..fe47aff8654283aa6a17a36226aa9fc7f18f9886 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1,5 +1,6 @@
package net.minecraft.server;
+import co.earthme.hearse.Hearse;
import co.earthme.hearse.HearseConfig;
import co.earthme.hearse.server.ServerEntityTickHook;
import com.google.common.base.Splitter;
@@ -399,8 +400,6 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Paper end
Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
this.paperConfigurations = services.paperConfigurations(); // Paper
- HearseConfig.init();
- ServerEntityTickHook.init();
}
// CraftBukkit end
@@ -914,11 +913,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper
// Paper start - kill main thread, and kill it hard
HearseConfig.save(); //Hearse
- try {
- ServerEntityTickHook.onServerStop(); //Hearse
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ Hearse.onServerStop();//Hearse
shutdownThread = Thread.currentThread();
org.spigotmc.WatchdogThread.doStop(); // Paper
if (!isSameThread()) {
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 1cc5cf3dcf33e89092b2aa689170c775007e4e4a..bfdde51d849b6e94af57bd23c0248ce34f020659 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -1,5 +1,6 @@
package net.minecraft.server.dedicated;
+import co.earthme.hearse.Hearse;
import com.google.common.collect.Lists;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.DataFixer;
@@ -225,6 +226,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
gg.pufferfish.pufferfish.PufferfishConfig.load(); // Pufferfish
gg.pufferfish.pufferfish.PufferfishCommand.init(); // Pufferfish
org.dreeam.leaf.LeafConfig.load(); // Leaf
+ Hearse.initAll(); //Hearse
this.setPvpAllowed(dedicatedserverproperties.pvp);
this.setFlightAllowed(dedicatedserverproperties.allowFlight);

View File

@@ -0,0 +1,187 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Wed, 11 Jan 2023 10:43:46 +0800
Subject: [PATCH] Hearse: Fix some hearse bugs
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/Hearse.java b/src/main/java/co/earthme/hearse/Hearse.java
index 79116449c221e0748e938f40366af03f93a4ab9f..f8fcb07bc54f4b150dacba325d0a47f0dc7687bc 100644
--- a/src/main/java/co/earthme/hearse/Hearse.java
+++ b/src/main/java/co/earthme/hearse/Hearse.java
@@ -16,7 +16,11 @@ public class Hearse {
public static void onServerStop(){
HearseConfig.save();
- workerManager.shutdownAllNow();
+ try {
+ workerManager.shutdownAll();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
}
public static WorkerThreadPoolManager getWorkerManager() {
diff --git a/src/main/java/co/earthme/hearse/commands/WorkerCommand.java b/src/main/java/co/earthme/hearse/commands/WorkerCommand.java
index 9bf8e0bdfed9a30a302c6369a727e8bb394b4670..1a4a6869a7278beadd97af006f4b5fae578b83ed 100644
--- a/src/main/java/co/earthme/hearse/commands/WorkerCommand.java
+++ b/src/main/java/co/earthme/hearse/commands/WorkerCommand.java
@@ -54,10 +54,10 @@ public class WorkerCommand extends Command {
searchedWorker.setCorePoolSize(Integer.parseInt(args[2]));
sender.sendMessage(ChatColor.GREEN+"Finished!");
}catch (NumberFormatException e){
- sender.sendMessage(ChatColor.RED+"Please supply a integer!");
+ sender.sendMessage(ChatColor.RED+"Please supply an integer!");
}
}else{
- sender.sendMessage(ChatColor.RED+"Please supply a integer!");
+ sender.sendMessage(ChatColor.RED+"Please supply an integer!");
}
break;
case "forceStop":
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
index 18c1f6ee4d4fc422fb2aa41483ce145d34fa39b1..fd7912df03ae39347206fe8db2efa7a8a0e516c8 100644
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
@@ -8,11 +8,15 @@ import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ServerEntityTickHook {
+ private static final Logger logger = LogManager.getLogger();
private static volatile boolean firstTick = false;
private static final WorkerThreadFactory defFactory = new DefaultWorkerFactory();
private static final AtomicInteger threadId = new AtomicInteger();
@@ -21,7 +25,7 @@ public class ServerEntityTickHook {
public static void executeAsyncTask(Runnable task){
if (!asyncEntityEnabled){
- throw new IllegalStateException();
+ throw new RejectedExecutionException();
}
worker.execute(task);
}
@@ -87,6 +91,11 @@ public class ServerEntityTickHook {
task.run();
return;
}
- worker.execute(task);
+ try {
+ worker.execute(task);
+ }catch (RejectedExecutionException e){
+ logger.warn("Worker rejected our task.Falling back to sync entity updating");
+ asyncEntityEnabled = false;
+ }
}
}
diff --git a/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java b/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java
index 90dd97491c0313bee031b81aa43fe6df3dda5b4f..b1eb341728f41c5a62e35944c4b0222758ae8eef 100644
--- a/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java
+++ b/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java
@@ -15,15 +15,19 @@ public class WorkerThreadPoolManager {
public void shutdownAll() throws InterruptedException {
for (WorkerThreadPoolExecutor worker : this.managedWorkers.values()){
- worker.shutdown();
- while (worker.awaitTermination(100, TimeUnit.MILLISECONDS)) {}
+ if (!worker.isShutdown()){
+ worker.shutdown();
+ while (worker.awaitTermination(100, TimeUnit.MILLISECONDS)) {}
+ }
}
}
+ @Deprecated
public Map<String, WorkerThreadPoolExecutor> getManagedWorkers() {
return Maps.newHashMap(this.managedWorkers);
}
+ @Deprecated
public WorkerThreadPoolExecutor getTargetWorker(String bound){
return this.managedWorkers.get(bound);
}
@@ -33,14 +37,16 @@ public class WorkerThreadPoolManager {
for (Map.Entry<String,WorkerThreadPoolExecutor> entry : this.managedWorkers.entrySet()){
final String workerName = entry.getKey();
final WorkerThreadPoolExecutor worker = entry.getValue();
- try {
- final List<Runnable> taskNotRunned = worker.shutdownNow();
- while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){
+ if (!worker.isShutdown()){
+ try {
+ final List<Runnable> taskNotRunned = worker.shutdownNow();
+ while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){
+ }
+ ret.put(workerName,taskNotRunned);
+ }catch (Exception e){
+ e.printStackTrace();
}
- ret.put(workerName,taskNotRunned);
- }catch (Exception e){
- e.printStackTrace();
}
}
return ret;
@@ -51,18 +57,20 @@ public class WorkerThreadPoolManager {
for (Map.Entry<String,WorkerThreadPoolExecutor> entry : this.managedWorkers.entrySet()){
final String workerName = entry.getKey();
final WorkerThreadPoolExecutor worker = entry.getValue();
- try {
- long timeCounter = timeOutCount;
- final List<Runnable> taskNotRunned = worker.shutdownNow();
- while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){
- if (timeCounter == 0){
- break;
+ if (!worker.isShutdown()){
+ try {
+ long timeCounter = timeOutCount;
+ final List<Runnable> taskNotRunned = worker.shutdownNow();
+ while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){
+ if (timeCounter == 0){
+ break;
+ }
+ timeCounter--;
}
- timeCounter--;
+ ret.put(workerName,taskNotRunned);
+ }catch (Exception e){
+ e.printStackTrace();
}
- ret.put(workerName,taskNotRunned);
- }catch (Exception e){
- e.printStackTrace();
}
}
return ret;
@@ -71,14 +79,16 @@ public class WorkerThreadPoolManager {
public void shutdownAll(long singleWorkerAwaitTimeOutCount) throws InterruptedException {
long counter = singleWorkerAwaitTimeOutCount;
for (WorkerThreadPoolExecutor worker : this.managedWorkers.values()){
- worker.shutdown();
- while (worker.awaitTermination(1, TimeUnit.MILLISECONDS)) {
- if (counter == 0){
- break;
+ if (!worker.isShutdown()){
+ worker.shutdown();
+ while (worker.awaitTermination(1, TimeUnit.MILLISECONDS)) {
+ if (counter == 0){
+ break;
+ }
+ counter--;
}
- counter--;
+ counter = singleWorkerAwaitTimeOutCount;
}
- counter = singleWorkerAwaitTimeOutCount;
}
}
}

View File

@@ -0,0 +1,28 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Wed, 11 Jan 2023 11:00:38 +0800
Subject: [PATCH] Hearse: Fix some concurrent problems
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
index 99142f749371828f6f55e4fbab03b22eb519ec1e..fc26edc5082f701e6450ca9abf78423840cd773c 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -111,14 +111,7 @@ public class GoalSelector {
}
}
- Iterator<Map.Entry<Goal.Flag, WrappedGoal>> iterator = this.lockedFlags.entrySet().iterator();
-
- while(iterator.hasNext()) {
- Map.Entry<Goal.Flag, WrappedGoal> entry = iterator.next();
- if (!entry.getValue().isRunning()) {
- iterator.remove();
- }
- }
+ this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning());
//profilerFiller.pop(); // Purpur
//profilerFiller.push("goalUpdate"); // Purpur

View File

@@ -0,0 +1,67 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Wed, 11 Jan 2023 16:58:19 +0800
Subject: [PATCH] Hearse: Fix some concurrent problems
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java
index 26e1b4060f2a93cb659170f83e6ce64086e0eb0c..d6951b05128fea7eb5f1b40837cea77e0c209165 100644
--- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java
+++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java
@@ -423,8 +423,10 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
final ChunkEntitySlices old = this.getChunk(entity.sectionX, entity.sectionZ);
final ChunkEntitySlices slices = this.getOrCreateChunk(newSectionX, newSectionZ);
- if (!old.removeEntity(entity, entity.sectionY)) {
- LOGGER.warn("Could not remove entity " + entity + " from its old chunk section (" + entity.sectionX + "," + entity.sectionY + "," + entity.sectionZ + ") since it was not contained in the section");
+ if (old!=null){
+ if (!old.removeEntity(entity, entity.sectionY)) {
+ LOGGER.warn("Could not remove entity " + entity + " from its old chunk section (" + entity.sectionX + "," + entity.sectionY + "," + entity.sectionZ + ") since it was not contained in the section");
+ }
}
if (!slices.addEntity(entity, newSectionY)) {
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
index 8db20db72cd51046213625fac46c35854c59ec5d..4d40526cc90c19ff5a1569c8d6d828a0d0b73ccb 100644
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
@@ -3,6 +3,7 @@ package net.minecraft.world.entity.ai.sensing;
import com.google.common.collect.ImmutableSet;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.longs.Long2LongMap;
+import it.unimi.dsi.fastutil.longs.Long2LongMaps;
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import java.util.Optional;
import java.util.Set;
@@ -23,7 +24,7 @@ public class NearestBedSensor extends Sensor<Mob> {
private static final int CACHE_TIMEOUT = 40;
private static final int BATCH_SIZE = 5;
private static final int RATE = 20;
- private final Long2LongMap batchCache = new Long2LongOpenHashMap();
+ private final Long2LongMap batchCache = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
private int triedCount;
private long lastUpdate;
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java
index 9babe636176da3c40598eb5bdac0919a1704eaa0..58c6b1f67aedf5ab2167fd070604fc0d8f710435 100644
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java
@@ -2,13 +2,14 @@ package net.minecraft.world.entity.ai.sensing;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
+import it.unimi.dsi.fastutil.ints.IntSets;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob;
public class Sensing {
private final Mob mob;
- private final IntSet seen = new IntOpenHashSet();
- private final IntSet unseen = new IntOpenHashSet();
+ private final IntSet seen = IntSets.synchronize(new IntOpenHashSet());
+ private final IntSet unseen = IntSets.synchronize(new IntOpenHashSet());
public Sensing(Mob owner) {
this.mob = owner;

View File

@@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Wed, 11 Jan 2023 20:24:40 +0800
Subject: [PATCH] Hearse: Fix some concurrent problems in LivingEntity
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 93c32dd39693b37efaa05af0486e1bdd298661f3..cdb33a430d0d1671899ab8bb0911193a5688af23 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -17,6 +17,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import net.minecraft.BlockUtil;
@@ -181,7 +182,7 @@ public abstract class LivingEntity extends Entity {
public static final float EXTRA_RENDER_CULLING_SIZE_WITH_BIG_HAT = 0.5F;
private final AttributeMap attributes;
public CombatTracker combatTracker = new CombatTracker(this);
- public final Map<MobEffect, MobEffectInstance> activeEffects = Maps.newHashMap();
+ public final Map<MobEffect, MobEffectInstance> activeEffects = Maps.newConcurrentMap();
private final NonNullList<ItemStack> lastHandItemStacks;
private final NonNullList<ItemStack> lastArmorItemStacks;
public boolean swinging;
@@ -257,7 +258,7 @@ public abstract class LivingEntity extends Entity {
// CraftBukkit start
public int expToDrop;
public boolean forceDrops;
- public ArrayList<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+ public List<org.bukkit.inventory.ItemStack> drops = new CopyOnWriteArrayList<>();
public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes;
public boolean collides = true;
public Set<UUID> collidableExemptions = new HashSet<>();
@@ -875,7 +876,7 @@ public abstract class LivingEntity extends Entity {
// CraftBukkit start
private boolean isTickingEffects = false;
- private List<ProcessableEffect> effectsToProcess = Lists.newArrayList();
+ private List<ProcessableEffect> effectsToProcess = Lists.newCopyOnWriteArrayList();
private static class ProcessableEffect {
@@ -1779,7 +1780,7 @@ public abstract class LivingEntity extends Entity {
}
}); // Paper end
this.postDeathDropItems(deathEvent); // Paper
- this.drops = new ArrayList<>();
+ this.drops = new CopyOnWriteArrayList<>();
// CraftBukkit end
// this.dropInventory();// CraftBukkit - moved up

View File

@@ -0,0 +1,126 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Wed, 11 Jan 2023 21:55:57 +0800
Subject: [PATCH] Hearse: Don't wait async tasks when stopping and change
something in CraftEventFactory
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/Hearse.java b/src/main/java/co/earthme/hearse/Hearse.java
index f8fcb07bc54f4b150dacba325d0a47f0dc7687bc..79116449c221e0748e938f40366af03f93a4ab9f 100644
--- a/src/main/java/co/earthme/hearse/Hearse.java
+++ b/src/main/java/co/earthme/hearse/Hearse.java
@@ -16,11 +16,7 @@ public class Hearse {
public static void onServerStop(){
HearseConfig.save();
- try {
- workerManager.shutdownAll();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ workerManager.shutdownAllNow();
}
public static WorkerThreadPoolManager getWorkerManager() {
diff --git a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
index 3e3ae10fcc54b80ff4ec433f136d15d3b9fa4fe4..443ac5267245c20830692b37802afd6ebdf8813b 100644
--- a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
+++ b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
@@ -9,12 +9,17 @@ public class DefaultWorkerFactory implements WorkerThreadFactory {
private static final AtomicInteger poolId = new AtomicInteger();
private final AtomicInteger threadId = new AtomicInteger();
+ public DefaultWorkerFactory(){
+ poolId.getAndIncrement();
+ }
+
@Override
public WorkerThread getNewThread(Runnable task) {
- final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.getAndIncrement()+"-worker-"+threadId.getAndIncrement());
+ final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement());
if (workerThread.isDaemon()){
workerThread.setDaemon(false);
}
+ workerThread.setDaemon(true);
workerThread.setPriority(Thread.NORM_PRIORITY - 2);
workerThread.setContextClassLoader(MinecraftServer.class.getClassLoader());
return workerThread;
diff --git a/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java b/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java
index b1eb341728f41c5a62e35944c4b0222758ae8eef..527dba288e1988773fd5a89f076f92084034f421 100644
--- a/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java
+++ b/src/main/java/co/earthme/hearse/workers/WorkerThreadPoolManager.java
@@ -16,6 +16,7 @@ public class WorkerThreadPoolManager {
public void shutdownAll() throws InterruptedException {
for (WorkerThreadPoolExecutor worker : this.managedWorkers.values()){
if (!worker.isShutdown()){
+ worker.getQueue().clear(); //Clear the tasks.We don't need wait them
worker.shutdown();
while (worker.awaitTermination(100, TimeUnit.MILLISECONDS)) {}
}
@@ -40,33 +41,6 @@ public class WorkerThreadPoolManager {
if (!worker.isShutdown()){
try {
final List<Runnable> taskNotRunned = worker.shutdownNow();
- while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){
-
- }
- ret.put(workerName,taskNotRunned);
- }catch (Exception e){
- e.printStackTrace();
- }
- }
- }
- return ret;
- }
-
- public Map<String,List<Runnable>> shutdownAllNow(long timeOutCount){
- final Map<String,List<Runnable>> ret = Maps.newHashMap();
- for (Map.Entry<String,WorkerThreadPoolExecutor> entry : this.managedWorkers.entrySet()){
- final String workerName = entry.getKey();
- final WorkerThreadPoolExecutor worker = entry.getValue();
- if (!worker.isShutdown()){
- try {
- long timeCounter = timeOutCount;
- final List<Runnable> taskNotRunned = worker.shutdownNow();
- while (worker.awaitTermination(1,TimeUnit.MILLISECONDS)){
- if (timeCounter == 0){
- break;
- }
- timeCounter--;
- }
ret.put(workerName,taskNotRunned);
}catch (Exception e){
e.printStackTrace();
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 6a52ae70b5f7fd9953b6b2605cae722f606e7fec..af5956bd57141cae08fe839bb2176988a48cd9b8 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -57,6 +57,7 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
+import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location; // Paper
import org.bukkit.Material;
@@ -229,7 +230,7 @@ public class CraftEventFactory {
public static final DamageSource MELTING = CraftDamageSource.copyOf(DamageSource.ON_FIRE);
public static final DamageSource POISON = CraftDamageSource.copyOf(DamageSource.MAGIC);
public static org.bukkit.block.Block blockDamage; // For use in EntityDamageByBlockEvent
- public static Entity entityDamage; // For use in EntityDamageByEntityEvent
+ public static volatile Entity entityDamage; // For use in EntityDamageByEntityEvent
// helper methods
private static boolean canBuild(ServerLevel world, Player player, int x, int z) {
@@ -1078,7 +1079,8 @@ public class CraftEventFactory {
} else if (source == DamageSource.MAGIC) {
cause = DamageCause.MAGIC;
} else {
- throw new IllegalStateException(String.format("Unhandled damage of %s by %s from %s", entity, damager.getHandle(), source.msgId));
+ LogManager.getLogger().error(String.format("Unhandled damage of %s by %s from %s", entity, damager.getHandle(), source.msgId));
+ cause = DamageCause.CUSTOM;
}
EntityDamageEvent event = new EntityDamageByEntityEvent(damager, entity.getBukkitEntity(), cause, modifiers, modifierFunctions, source.isCritical()); // Paper - add critical damage API
event.setCancelled(cancelled);

View File

@@ -0,0 +1,223 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Thu, 12 Jan 2023 13:04:01 +0800
Subject: [PATCH] Hearse: Parallel world ticking
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
index 443ac5267245c20830692b37802afd6ebdf8813b..c26511c26bd02320a55a01168f342b4b051ffdfd 100644
--- a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
+++ b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
@@ -8,14 +8,16 @@ import java.util.concurrent.atomic.AtomicInteger;
public class DefaultWorkerFactory implements WorkerThreadFactory {
private static final AtomicInteger poolId = new AtomicInteger();
private final AtomicInteger threadId = new AtomicInteger();
+ private final String bound;
- public DefaultWorkerFactory(){
+ public DefaultWorkerFactory(String bound){
poolId.getAndIncrement();
+ this.bound = bound;
}
@Override
public WorkerThread getNewThread(Runnable task) {
- final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement());
+ final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()+"-bound-"+this.bound);
if (workerThread.isDaemon()){
workerThread.setDaemon(false);
}
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
index fd7912df03ae39347206fe8db2efa7a8a0e516c8..9d26ff7d07f1e972f1720f5b2d0e66d4c9c3f1e5 100644
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
@@ -18,7 +18,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class ServerEntityTickHook {
private static final Logger logger = LogManager.getLogger();
private static volatile boolean firstTick = false;
- private static final WorkerThreadFactory defFactory = new DefaultWorkerFactory();
+ private static final WorkerThreadFactory defFactory = new DefaultWorkerFactory("entity");
private static final AtomicInteger threadId = new AtomicInteger();
private static WorkerThreadPoolExecutor worker;
private static boolean asyncEntityEnabled;
diff --git a/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
new file mode 100644
index 0000000000000000000000000000000000000000..5670fdae5d16cbbdf605df048ae253208e49a82c
--- /dev/null
+++ b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
@@ -0,0 +1,70 @@
+package co.earthme.hearse.server;
+
+import co.earthme.hearse.Hearse;
+import co.earthme.hearse.HearseConfig;
+import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
+import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory;
+import net.minecraft.CrashReport;
+import net.minecraft.ReportedException;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.BooleanSupplier;
+
+public class ServerLevelTickHook {
+ private static final DefaultWorkerFactory workerFactory = new DefaultWorkerFactory("world");
+ private static WorkerThreadPoolExecutor worker;
+ private static boolean enabledParaWorld;
+ private static volatile boolean inited = false;
+ private static final AtomicInteger activeTaskCount = new AtomicInteger();
+
+ public static void initWorker(){
+ enabledParaWorld = HearseConfig.getBoolean("optimizations.enableparallelworldtick",true);
+ if (enabledParaWorld){
+ worker = new WorkerThreadPoolExecutor(
+ MinecraftServer.getServer().levels.size(),
+ MinecraftServer.getServer().levels.size(),
+ 0,
+ TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<>(),
+ workerFactory
+ );
+ worker.prestartAllCoreThreads();
+ Hearse.getWorkerManager().addWorker("world",worker);
+ }
+ inited = true;
+ }
+
+ public static boolean isInited(){
+ return inited;
+ }
+
+ public static void callWorldTick(ServerLevel worldserver, BooleanSupplier shouldKeepTicking){
+ activeTaskCount.getAndIncrement();
+ worker.execute(()->{
+ try {
+ try {
+ worldserver.tick(shouldKeepTicking);
+ for (final io.papermc.paper.chunk.SingleThreadChunkRegionManager regionManager : worldserver.getChunkSource().chunkMap.regionManagers) {
+ regionManager.recalculateRegions();
+ }
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+ worldserver.explosionDensityCache.clear();
+ }finally {
+ activeTaskCount.getAndDecrement();
+ }
+ });
+ }
+
+ public static void awaitWorldTicKTasks(){
+ while (activeTaskCount.get() > 0){
+ LockSupport.parkNanos("Await world ticking",1000000);
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index fe47aff8654283aa6a17a36226aa9fc7f18f9886..57bae261ee1d6db734b38dd5f67dbce98c41fc1c 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -3,6 +3,7 @@ package net.minecraft.server;
import co.earthme.hearse.Hearse;
import co.earthme.hearse.HearseConfig;
import co.earthme.hearse.server.ServerEntityTickHook;
+import co.earthme.hearse.server.ServerLevelTickHook;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
@@ -223,7 +224,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private String localIp;
private int port;
private final LayeredRegistryAccess<RegistryLayer> registries;
- private Map<ResourceKey<Level>, ServerLevel> levels;
+ public Map<ResourceKey<Level>, ServerLevel> levels;
private PlayerList playerList;
private volatile boolean running;
private volatile boolean isRestarting = false; // Paper - flag to signify we're attempting to restart
@@ -1121,6 +1122,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
Arrays.fill( recentTps, 20 );
long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop
lastTick = start - TICK_TIME; // Paper
+ ServerLevelTickHook.initWorker(); //Hearse
while (this.running) {
// Paper start - rewrite chunk system
// guarantee that nothing can stop the server from halting if it can at least still tick
@@ -1515,11 +1517,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
//MinecraftTimings.timeUpdateTimer.stopTiming(); // Spigot // Paper // Purpur
this.isIteratingOverLevels = true; // Paper
- Iterator iterator = this.getAllLevels().iterator(); // Paper - move down
- while (iterator.hasNext()) {
- ServerLevel worldserver = (ServerLevel) iterator.next();
- worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
- worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
+ for (ServerLevel worldserver : this.getAllLevels()) {
+ worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
+ worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper
/*this.profiler.push(() -> { // Purpur
@@ -1534,35 +1534,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// CraftBukkit end */
//this.profiler.push("tick"); // Purpur
-
- try {
- //worldserver.timings.doTick.startTiming(); // Spigot // Purpur
- worldserver.tick(shouldKeepTicking);
- // Paper start
- for (final io.papermc.paper.chunk.SingleThreadChunkRegionManager regionManager : worldserver.getChunkSource().chunkMap.regionManagers) {
- regionManager.recalculateRegions();
- }
- // Paper end
- //worldserver.timings.doTick.stopTiming(); // Spigot // Purpur
- } catch (Throwable throwable) {
- // Spigot Start
- CrashReport crashreport;
- try {
- crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
- } catch (Throwable t) {
- if (throwable instanceof ThreadDeath) { throw (ThreadDeath)throwable; } // Paper
- throw new RuntimeException("Error generating crash report", t);
- }
- // Spigot End
-
- worldserver.fillReportDetails(crashreport);
- throw new ReportedException(crashreport);
- }
-
- //this.profiler.pop(); // Purpur
- //this.profiler.pop(); // Purpur
- worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
+ ServerLevelTickHook.callWorldTick(worldserver,shouldKeepTicking);
}
+ ServerLevelTickHook.awaitWorldTicKTasks();
this.isIteratingOverLevels = false; // Paper
//this.profiler.popPush("connection"); // Purpur
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index de78c5bdde53b4adfed9fda4d473560849bdb5aa..4a75c2895f4f5e3229be3c7b177445611a1e70b6 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -7,6 +7,7 @@ import com.destroystokyo.paper.event.server.ServerExceptionEvent;
import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.mojang.serialization.Codec;
import java.io.IOException;
import java.util.Iterator;
@@ -179,7 +180,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
- public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = Maps.newConcurrentMap(); // Paper - Optimize explosions
public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
// Paper start - fix and optimise world upgrading

View File

@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Thu, 12 Jan 2023 13:57:52 +0800
Subject: [PATCH] Hearse: Fix some concurrent problems in Entity.java
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index f33476a35706d7a236fe3bb178d166d568c07674..483c19ac24b074cbdb924d684c0892ddc546af3e 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -24,6 +24,8 @@ import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.annotation.Nullable;
+
+import it.unimi.dsi.fastutil.objects.Object2DoubleMaps;
import net.minecraft.BlockUtil;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
@@ -511,14 +513,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
this.nextStep = 1.0F;
this.random = SHARED_RANDOM; // Paper
this.remainingFireTicks = -this.getFireImmuneTicks();
- this.fluidHeight = new Object2DoubleArrayMap(2);
- this.fluidOnEyes = new HashSet();
+ this.fluidHeight = Object2DoubleMaps.synchronize(new Object2DoubleArrayMap(2));
+ this.fluidOnEyes = Sets.newConcurrentHashSet();
this.firstTick = true;
this.levelCallback = EntityInLevelCallback.NULL;
this.packetPositionCodec = new VecDeltaCodec();
this.uuid = Mth.createInsecureUUID(this.random);
this.stringUUID = this.uuid.toString();
- this.tags = Sets.newHashSet();
+ this.tags = Sets.newConcurrentHashSet();
this.pistonDeltas = new double[]{0.0D, 0.0D, 0.0D};
this.feetBlockState = null;
this.type = type;

View File

@@ -0,0 +1,102 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Thu, 12 Jan 2023 13:58:20 +0800
Subject: [PATCH] Hearse: Print world worker thread names when server started
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
index c26511c26bd02320a55a01168f342b4b051ffdfd..03a29509821a17faac2dc8ab810a2693b03bfbc6 100644
--- a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
+++ b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java
@@ -2,25 +2,38 @@ package co.earthme.hearse.concurrent.threadfactory;
import co.earthme.hearse.concurrent.WorkerThread;
import co.earthme.hearse.concurrent.WorkerThreadFactory;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import it.unimi.dsi.fastutil.objects.ObjectLists;
import net.minecraft.server.MinecraftServer;
+
+import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class DefaultWorkerFactory implements WorkerThreadFactory {
private static final AtomicInteger poolId = new AtomicInteger();
private final AtomicInteger threadId = new AtomicInteger();
private final String bound;
+ private final List<Thread> createdThreads = ObjectLists.synchronize(new ObjectArrayList<>());
public DefaultWorkerFactory(String bound){
poolId.getAndIncrement();
this.bound = bound;
}
+ public List<Thread> getCreatedThreads() {
+ return this.createdThreads;
+ }
+
@Override
public WorkerThread getNewThread(Runnable task) {
- final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()+"-bound-"+this.bound);
- if (workerThread.isDaemon()){
- workerThread.setDaemon(false);
- }
+ final WorkerThread workerThread = new WorkerThread(()->{
+ try {
+ task.run();
+ }finally {
+ this.createdThreads.remove(Thread.currentThread());
+ }
+ },"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()+"-bound-"+this.bound);
+ this.createdThreads.add(workerThread);
workerThread.setDaemon(true);
workerThread.setPriority(Thread.NORM_PRIORITY - 2);
workerThread.setContextClassLoader(MinecraftServer.class.getClassLoader());
diff --git a/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
index 5670fdae5d16cbbdf605df048ae253208e49a82c..8085eb700d8e5c20ebb5bfeceb78198c6e973019 100644
--- a/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java
@@ -2,12 +2,15 @@ package co.earthme.hearse.server;
import co.earthme.hearse.Hearse;
import co.earthme.hearse.HearseConfig;
+import co.earthme.hearse.concurrent.WorkerThread;
import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor;
import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory;
import net.minecraft.CrashReport;
import net.minecraft.ReportedException;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -21,6 +24,7 @@ public class ServerLevelTickHook {
private static boolean enabledParaWorld;
private static volatile boolean inited = false;
private static final AtomicInteger activeTaskCount = new AtomicInteger();
+ private static final Logger logger = LogManager.getLogger();
public static void initWorker(){
enabledParaWorld = HearseConfig.getBoolean("optimizations.enableparallelworldtick",true);
@@ -28,13 +32,17 @@ public class ServerLevelTickHook {
worker = new WorkerThreadPoolExecutor(
MinecraftServer.getServer().levels.size(),
MinecraftServer.getServer().levels.size(),
- 0,
+ Long.MAX_VALUE,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
workerFactory
);
+ worker.allowCoreThreadTimeOut(true);
worker.prestartAllCoreThreads();
Hearse.getWorkerManager().addWorker("world",worker);
+ for (Thread worker : workerFactory.getCreatedThreads()){
+ logger.warn("World worker name:{}.This can help you to slove the lag problems when you using parallel world ticking",worker.getName());
+ }
}
inited = true;
}

View File

@@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Thu, 12 Jan 2023 16:08:30 +0800
Subject: [PATCH] Hearse: Fix some NPE errors
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index cdb33a430d0d1671899ab8bb0911193a5688af23..c72920a17178059a29d21e96aeef398f6e0bbbdc 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1964,6 +1964,10 @@ public abstract class LivingEntity extends Entity {
BlockPos blockposition = this.blockPosition();
BlockState iblockdata = this.getFeetBlockState();
+ if (iblockdata == null){
+ return false;
+ }
+
if (iblockdata.is(BlockTags.CLIMBABLE)) {
this.lastClimbablePos = Optional.of(blockposition);
return true;
diff --git a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
index 0c308e12f9b590fa169babac487c8adc7e3f823c..b61ed4d03848f86ca5e93b0374bbf4ca05369ad2 100644
--- a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
+++ b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
@@ -5,12 +5,16 @@ import com.google.common.collect.Sets;
import java.util.*;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import it.unimi.dsi.fastutil.objects.ObjectList;
+import it.unimi.dsi.fastutil.objects.ObjectLists;
+import net.himeki.mcmtfabric.parallelised.ConcurrentDoublyLinkedList;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.phys.Vec3;
public class EuclideanGameEventListenerRegistry implements GameEventListenerRegistry {
- private final List<GameEventListener> listeners = Collections.synchronizedList(Lists.newArrayList());
+ private final List<GameEventListener> listeners = new ConcurrentDoublyLinkedList<>();
private final Set<GameEventListener> listenersToRemove = Sets.newConcurrentHashSet();
private final List<GameEventListener> listenersToAdd = Lists.newCopyOnWriteArrayList();
private boolean processing;

View File

@@ -0,0 +1,585 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Thu, 12 Jan 2023 19:43:48 +0800
Subject: [PATCH] Hearse: Move player ticking to main thread and add lock in
ChunkEntitySlices
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
index 9d26ff7d07f1e972f1720f5b2d0e66d4c9c3f1e5..86f8afd54c0cbb449403c3f43e6880ade13cfecc 100644
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
@@ -8,6 +8,7 @@ import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.player.Player;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.concurrent.LinkedBlockingQueue;
@@ -87,7 +88,7 @@ public class ServerEntityTickHook {
}
}
};
- if (!asyncEntityEnabled){
+ if (!asyncEntityEnabled || entity instanceof Player){
task.run();
return;
}
diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
index ae22ca9ea5fd3d78d8c5bf9f1ab96f1129fddc11..1012b8d1d192a946b0982c88c12a0fc0e6051972 100644
--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
+++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
@@ -33,7 +33,7 @@ public final class ChunkEntitySlices {
public final int chunkX;
public final int chunkZ;
protected final ServerLevel world;
-
+ protected final StampedLock accessLock = new StampedLock(); //Hearse -- fix some entity can't be removed
protected final EntityCollectionBySection allEntities;
protected final EntityCollectionBySection hardCollidingEntities;
protected final Reference2ObjectMap<Class<? extends Entity>, EntityCollectionBySection> entitiesByClass;
@@ -70,68 +70,82 @@ public final class ChunkEntitySlices {
// Paper start - optimise CraftChunk#getEntities
public org.bukkit.entity.Entity[] getChunkEntities() {
- List<org.bukkit.entity.Entity> ret = new java.util.ArrayList<>();
- final Entity[] entities = this.entities.getRawData();
- for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
- final Entity entity = entities[i];
- if (entity == null) {
- continue;
- }
- final org.bukkit.entity.Entity bukkit = entity.getBukkitEntity();
- if (bukkit != null && bukkit.isValid()) {
- ret.add(bukkit);
+ final long id = this.accessLock.readLock();
+ try {
+ List<org.bukkit.entity.Entity> ret = new java.util.ArrayList<>();
+ final Entity[] entities = this.entities.getRawData();
+ for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
+ final Entity entity = entities[i];
+ if (entity == null) {
+ continue;
+ }
+ final org.bukkit.entity.Entity bukkit = entity.getBukkitEntity();
+ if (bukkit != null && bukkit.isValid()) {
+ ret.add(bukkit);
+ }
}
+ return ret.toArray(new org.bukkit.entity.Entity[0]);
+ } finally {
+ this.accessLock.unlockRead(id);
}
-
- return ret.toArray(new org.bukkit.entity.Entity[0]);
}
public CompoundTag save() {
- final int len = this.entities.size();
- if (len == 0) {
- return null;
- }
+ final long id = this.accessLock.readLock();
+ try {
+ final int len = this.entities.size();
+ if (len == 0) {
+ return null;
+ }
- final Entity[] rawData = this.entities.getRawData();
- final List<Entity> collectedEntities = new ArrayList<>(len);
- for (int i = 0; i < len; ++i) {
- final Entity entity = rawData[i];
- if (entity.shouldBeSaved()) {
- collectedEntities.add(entity);
+ final Entity[] rawData = this.entities.getRawData();
+ final List<Entity> collectedEntities = new ArrayList<>(len);
+ for (int i = 0; i < len; ++i) {
+ final Entity entity = rawData[i];
+ if (entity.shouldBeSaved()) {
+ collectedEntities.add(entity);
+ }
}
- }
- if (collectedEntities.isEmpty()) {
- return null;
- }
+ if (collectedEntities.isEmpty()) {
+ return null;
+ }
- return EntityStorage.saveEntityChunk(collectedEntities, new ChunkPos(this.chunkX, this.chunkZ), this.world);
+ return EntityStorage.saveEntityChunk(collectedEntities, new ChunkPos(this.chunkX, this.chunkZ), this.world);
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
}
// returns true if this chunk has transient entities remaining
public boolean unload() {
- final int len = this.entities.size();
- final Entity[] collectedEntities = Arrays.copyOf(this.entities.getRawData(), len);
-
- for (int i = 0; i < len; ++i) {
- final Entity entity = collectedEntities[i];
- if (entity.isRemoved()) {
- // removed by us below
- continue;
- }
- if (entity.shouldBeSaved()) {
- entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK);
- if (entity.isVehicle()) {
- // we cannot assume that these entities are contained within this chunk, because entities can
- // desync - so we need to remove them all
- for (final Entity passenger : entity.getIndirectPassengers()) {
- passenger.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK);
+ long id = this.accessLock.readLock();
+ try {
+ final int len = this.entities.size();
+ final Entity[] collectedEntities = Arrays.copyOf(this.entities.getRawData(), len);
+
+ for (int i = 0; i < len; ++i) {
+ final Entity entity = collectedEntities[i];
+ if (entity.isRemoved()) {
+ // removed by us below
+ continue;
+ }
+ if (entity.shouldBeSaved()) {
+ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK);
+ if (entity.isVehicle()) {
+ // we cannot assume that these entities are contained within this chunk, because entities can
+ // desync - so we need to remove them all
+ for (final Entity passenger : entity.getIndirectPassengers()) {
+ passenger.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK);
+ }
}
}
}
- }
- return this.entities.size() != 0;
+ return this.entities.size() != 0;
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
}
private List<Entity> getAllEntities() {
@@ -142,42 +156,65 @@ public final class ChunkEntitySlices {
final Entity[] rawData = this.entities.getRawData();
final List<Entity> collectedEntities = new ArrayList<>(len);
- for (int i = 0; i < len; ++i) {
- collectedEntities.add(rawData[i]);
- }
+ collectedEntities.addAll(Arrays.asList(rawData).subList(0, len));
return collectedEntities;
}
public void callEntitiesLoadEvent() {
- CraftEventFactory.callEntitiesLoadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
+ final long id = this.accessLock.readLock();
+ try {
+ CraftEventFactory.callEntitiesLoadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
}
public void callEntitiesUnloadEvent() {
- CraftEventFactory.callEntitiesUnloadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
+ final long id = this.accessLock.readLock();
+ try {
+ CraftEventFactory.callEntitiesUnloadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
}
// Paper end - optimise CraftChunk#getEntities
public boolean isEmpty() {
- return this.entities.size() == 0;
+ final long id = this.accessLock.readLock();
+ try {
+ return this.entities.size() == 0;
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
}
public void mergeInto(final ChunkEntitySlices slices) {
- final Entity[] entities = this.entities.getRawData();
- for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
- final Entity entity = entities[i];
- slices.addEntity(entity, entity.sectionY);
+ final long id = this.accessLock.readLock();
+ try {
+ final Entity[] entities = this.entities.getRawData();
+ for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
+ final Entity entity = entities[i];
+ slices.addEntity(entity, entity.sectionY);
+ }
+ } finally {
+ this.accessLock.unlockRead(id);
}
}
public void updateStatus(final ChunkHolder.FullChunkStatus status, final EntityLookup lookup) {
this.status = status;
- final Entity[] entities = this.entities.getRawData();
+ Entity[] entities;
- for (int i = 0, size = this.entities.size(); i < size; ++i) {
- final Entity entity = entities[i];
+ final long id = this.accessLock.readLock();
+ try {
+ entities = Arrays.copyOf(this.entities.getRawData(), this.entities.getRawData().length);
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
+ for (final Entity entity : entities) {
final Visibility oldVisibility = EntityLookup.getEntityStatus(entity);
entity.chunkStatus = status;
final Visibility newVisibility = EntityLookup.getEntityStatus(entity);
@@ -187,70 +224,95 @@ public final class ChunkEntitySlices {
}
public boolean addEntity(final Entity entity, final int chunkSection) {
- if (!this.entities.add(entity)) {
- return false;
- }
- entity.chunkStatus = this.status;
- final int sectionIndex = chunkSection - this.minSection;
-
- this.allEntities.addEntity(entity, sectionIndex);
+ long id = this.accessLock.writeLock();
+ try {
+ if (!this.entities.add(entity)) {
+ return false;
+ }
+ entity.chunkStatus = this.status;
+ final int sectionIndex = chunkSection - this.minSection;
- if (entity.hardCollides()) {
- this.hardCollidingEntities.addEntity(entity, sectionIndex);
- }
+ this.allEntities.addEntity(entity, sectionIndex);
- for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
- this.entitiesByClass.reference2ObjectEntrySet().iterator(); iterator.hasNext();) {
- final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
+ if (entity.hardCollides()) {
+ this.hardCollidingEntities.addEntity(entity, sectionIndex);
+ }
- if (entry.getKey().isInstance(entity)) {
- entry.getValue().addEntity(entity, sectionIndex);
+ for (final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry : this.entitiesByClass.reference2ObjectEntrySet()) {
+ if (entry.getKey().isInstance(entity)) {
+ entry.getValue().addEntity(entity, sectionIndex);
+ }
}
+ } finally {
+ this.accessLock.unlockWrite(id);
}
-
return true;
}
public boolean removeEntity(final Entity entity, final int chunkSection) {
- if (!this.entities.remove(entity)) {
- return false;
- }
- entity.chunkStatus = null;
- final int sectionIndex = chunkSection - this.minSection;
-
- this.allEntities.removeEntity(entity, sectionIndex);
+ long id = this.accessLock.writeLock();
+ try {
+ if (!this.entities.remove(entity)) {
+ return false;
+ }
+ entity.chunkStatus = null;
+ final int sectionIndex = chunkSection - this.minSection;
- if (entity.hardCollides()) {
- this.hardCollidingEntities.removeEntity(entity, sectionIndex);
- }
+ this.allEntities.removeEntity(entity, sectionIndex);
- for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
- this.entitiesByClass.reference2ObjectEntrySet().iterator(); iterator.hasNext();) {
- final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
+ if (entity.hardCollides()) {
+ this.hardCollidingEntities.removeEntity(entity, sectionIndex);
+ }
- if (entry.getKey().isInstance(entity)) {
- entry.getValue().removeEntity(entity, sectionIndex);
+ for (final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry : this.entitiesByClass.reference2ObjectEntrySet()) {
+ if (entry.getKey().isInstance(entity)) {
+ entry.getValue().removeEntity(entity, sectionIndex);
+ }
}
+ } finally {
+ this.accessLock.unlockWrite(id);
}
-
return true;
}
public void getHardCollidingEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
- this.hardCollidingEntities.getEntities(except, box, into, predicate);
+ final long id = this.accessLock.readLock();
+ try {
+ this.hardCollidingEntities.getEntities(except, box, into, predicate);
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
}
public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
- this.allEntities.getEntitiesWithEnderDragonParts(except, box, into, predicate);
+ final long id = this.accessLock.readLock();
+ try {
+ this.allEntities.getEntitiesWithEnderDragonParts(except, box, into, predicate);
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
+
}
public void getEntitiesWithoutDragonParts(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
- this.allEntities.getEntities(except, box, into, predicate);
+ final long id = this.accessLock.readLock();
+ try {
+ this.allEntities.getEntities(except, box, into, predicate);
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
+
}
public <T extends Entity> void getEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
final Predicate<? super T> predicate) {
- this.allEntities.getEntities(type, box, (List)into, (Predicate)predicate);
+ final long id = this.accessLock.readLock();
+ try {
+ this.allEntities.getEntities(type, box, (List) into, (Predicate) predicate);
+ } finally {
+ this.accessLock.unlockRead(id);
+ }
+
}
protected EntityCollectionBySection initClass(final Class<? extends Entity> clazz) {
@@ -278,12 +340,17 @@ public final class ChunkEntitySlices {
public <T extends Entity> void getEntities(final Class<? extends T> clazz, final Entity except, final AABB box, final List<? super T> into,
final Predicate<? super T> predicate) {
- EntityCollectionBySection collection = this.entitiesByClass.get(clazz);
- if (collection != null) {
- collection.getEntitiesWithEnderDragonParts(except, clazz, box, (List)into, (Predicate)predicate);
- } else {
- this.entitiesByClass.putIfAbsent(clazz, collection = this.initClass(clazz));
- collection.getEntitiesWithEnderDragonParts(except, clazz, box, (List)into, (Predicate)predicate);
+ final long id = this.accessLock.readLock();
+ try {
+ EntityCollectionBySection collection = this.entitiesByClass.get(clazz);
+ if (collection != null) {
+ collection.getEntitiesWithEnderDragonParts(except, clazz, box, (List) into, (Predicate) predicate);
+ } else {
+ this.entitiesByClass.putIfAbsent(clazz, collection = this.initClass(clazz));
+ collection.getEntitiesWithEnderDragonParts(except, clazz, box, (List) into, (Predicate) predicate);
+ }
+ } finally {
+ this.accessLock.unlockRead(id);
}
}
@@ -300,7 +367,7 @@ public final class ChunkEntitySlices {
}
public BasicEntityList(final int cap) {
- this.storage = (E[])(cap <= 0 ? EMPTY : new Entity[cap]);
+ this.storage = (E[]) (cap <= 0 ? EMPTY : new Entity[cap]);
}
public synchronized boolean isEmpty() {
@@ -313,7 +380,7 @@ public final class ChunkEntitySlices {
private void resize() {
if (this.storage == EMPTY) {
- this.storage = (E[])new Entity[DEFAULT_CAPACITY];
+ this.storage = (E[]) new Entity[DEFAULT_CAPACITY];
} else {
this.storage = Arrays.copyOf(this.storage, this.storage.length * 2);
}
@@ -396,7 +463,7 @@ public final class ChunkEntitySlices {
list.add(entity);
++this.count;
- }finally {
+ } finally {
this.listLock.unlockWrite(id);
}
}
@@ -416,7 +483,7 @@ public final class ChunkEntitySlices {
this.entitiesBySection[sectionIndex] = null;
this.nonEmptyBitset[sectionIndex >>> 6] ^= (1L << (sectionIndex & (Long.SIZE - 1)));
}
- }finally {
+ } finally {
this.listLock.unlockWrite(id);
}
}
@@ -459,65 +526,65 @@ public final class ChunkEntitySlices {
into.add(entity);
}
}
- }finally {
+ } finally {
this.listLock.unlockRead(id);
}
}
public void getEntitiesWithEnderDragonParts(final Entity except, final AABB box, final List<Entity> into,
final Predicate<? super Entity> predicate) {
- final long id = this.listLock.readLock();
- try {
- if (this.count == 0) {
- return;
- }
+ final long id = this.listLock.readLock();
+ try {
+ if (this.count == 0) {
+ return;
+ }
- final int minSection = this.manager.minSection;
- final int maxSection = this.manager.maxSection;
+ final int minSection = this.manager.minSection;
+ final int maxSection = this.manager.maxSection;
- final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
- final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
- final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
+ final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
- for (int section = min; section <= max; ++section) {
- final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
+ for (int section = min; section <= max; ++section) {
+ final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
- if (list == null) {
- continue;
- }
+ if (list == null) {
+ continue;
+ }
- final Entity[] storage = list.storage;
+ final Entity[] storage = list.storage;
- for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
- final Entity entity = storage[i];
+ for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
+ final Entity entity = storage[i];
- if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
- continue;
- }
+ if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
+ continue;
+ }
- if (predicate == null || predicate.test(entity)) {
- into.add(entity);
- } // else: continue to test the ender dragon parts
+ if (predicate == null || predicate.test(entity)) {
+ into.add(entity);
+ } // else: continue to test the ender dragon parts
- if (entity instanceof EnderDragon) {
- for (final EnderDragonPart part : ((EnderDragon)entity).subEntities) {
- if (part == except || !part.getBoundingBox().intersects(box)) {
- continue;
- }
+ if (entity instanceof EnderDragon) {
+ for (final EnderDragonPart part : ((EnderDragon) entity).subEntities) {
+ if (part == except || !part.getBoundingBox().intersects(box)) {
+ continue;
+ }
- if (predicate != null && !predicate.test(part)) {
- continue;
- }
+ if (predicate != null && !predicate.test(part)) {
+ continue;
+ }
- into.add(part);
- }
- }
- }
- }
- }finally {
- this.listLock.unlockRead(id);
- }
+ into.add(part);
+ }
+ }
+ }
+ }
+ } finally {
+ this.listLock.unlockRead(id);
+ }
}
public void getEntitiesWithEnderDragonParts(final Entity except, final Class<?> clazz, final AABB box, final List<Entity> into,
@@ -557,7 +624,7 @@ public final class ChunkEntitySlices {
} // else: continue to test the ender dragon parts
if (entity instanceof EnderDragon) {
- for (final EnderDragonPart part : ((EnderDragon)entity).subEntities) {
+ for (final EnderDragonPart part : ((EnderDragon) entity).subEntities) {
if (part == except || !part.getBoundingBox().intersects(box) || !clazz.isInstance(part)) {
continue;
}
@@ -571,7 +638,7 @@ public final class ChunkEntitySlices {
}
}
}
- }finally {
+ } finally {
this.listLock.unlockRead(id);
}
}
@@ -608,14 +675,14 @@ public final class ChunkEntitySlices {
continue;
}
- if (predicate != null && !predicate.test((T)entity)) {
+ if (predicate != null && !predicate.test((T) entity)) {
continue;
}
- into.add((T)entity);
+ into.add((T) entity);
}
}
- }finally {
+ } finally {
this.listLock.unlockRead(id);
}
}

View File

@@ -0,0 +1,460 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Thu, 12 Jan 2023 20:18:22 +0800
Subject: [PATCH] Hearse: Remove some lock in ChunkEntitySlices
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
index 1012b8d1d192a946b0982c88c12a0fc0e6051972..b2eb6feffb2191c450175547c1371623ce5185eb 100644
--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
+++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
@@ -191,15 +191,19 @@ public final class ChunkEntitySlices {
public void mergeInto(final ChunkEntitySlices slices) {
final long id = this.accessLock.readLock();
+ final List<Entity> cop = new ArrayList<>();
try {
final Entity[] entities = this.entities.getRawData();
for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
final Entity entity = entities[i];
- slices.addEntity(entity, entity.sectionY);
+ cop.add(entity);
}
} finally {
this.accessLock.unlockRead(id);
}
+ for (Entity entity : cop){
+ slices.addEntity(entity, entity.sectionY);
+ }
}
public void updateStatus(final ChunkHolder.FullChunkStatus status, final EntityLookup lookup) {
@@ -370,11 +374,11 @@ public final class ChunkEntitySlices {
this.storage = (E[]) (cap <= 0 ? EMPTY : new Entity[cap]);
}
- public synchronized boolean isEmpty() {
+ public boolean isEmpty() {
return this.size == 0;
}
- public synchronized int size() {
+ public int size() {
return this.size;
}
@@ -386,7 +390,7 @@ public final class ChunkEntitySlices {
}
}
- public synchronized void add(final E entity) {
+ public void add(final E entity) {
final int idx = this.size++;
if (idx >= this.storage.length) {
this.resize();
@@ -396,7 +400,7 @@ public final class ChunkEntitySlices {
}
}
- public synchronized int indexOf(final E entity) {
+ public int indexOf(final E entity) {
final E[] storage = this.storage;
for (int i = 0, len = Math.min(this.storage.length, this.size); i < len; ++i) {
@@ -408,7 +412,7 @@ public final class ChunkEntitySlices {
return -1;
}
- public synchronized boolean remove(final E entity) {
+ public boolean remove(final E entity) {
final int idx = this.indexOf(entity);
if (idx == -1) {
return false;
@@ -425,7 +429,7 @@ public final class ChunkEntitySlices {
return true;
}
- public synchronized boolean has(final E entity) {
+ public boolean has(final E entity) {
return this.indexOf(entity) != -1;
}
}
@@ -436,7 +440,6 @@ public final class ChunkEntitySlices {
protected final long[] nonEmptyBitset;
protected final BasicEntityList<Entity>[] entitiesBySection;
protected int count;
- private final StampedLock listLock = new StampedLock();//Hearse
public EntityCollectionBySection(final ChunkEntitySlices manager) {
this.manager = manager;
@@ -448,242 +451,212 @@ public final class ChunkEntitySlices {
}
public void addEntity(final Entity entity, final int sectionIndex) {
- final long id = this.listLock.writeLock();
- try {
- BasicEntityList<Entity> list = this.entitiesBySection[sectionIndex];
-
- if (list != null && list.has(entity)) {
- return;
- }
+ BasicEntityList<Entity> list = this.entitiesBySection[sectionIndex];
- if (list == null) {
- this.entitiesBySection[sectionIndex] = list = new BasicEntityList<>();
- this.nonEmptyBitset[sectionIndex >>> 6] |= (1L << (sectionIndex & (Long.SIZE - 1)));
- }
+ if (list != null && list.has(entity)) {
+ return;
+ }
- list.add(entity);
- ++this.count;
- } finally {
- this.listLock.unlockWrite(id);
+ if (list == null) {
+ this.entitiesBySection[sectionIndex] = list = new BasicEntityList<>();
+ this.nonEmptyBitset[sectionIndex >>> 6] |= (1L << (sectionIndex & (Long.SIZE - 1)));
}
+
+ list.add(entity);
+ ++this.count;
}
public void removeEntity(final Entity entity, final int sectionIndex) {
- final long id = this.listLock.writeLock();
- try {
- final BasicEntityList<Entity> list = this.entitiesBySection[sectionIndex];
+ final BasicEntityList<Entity> list = this.entitiesBySection[sectionIndex];
- if (list == null || !list.remove(entity)) {
- return;
- }
+ if (list == null || !list.remove(entity)) {
+ return;
+ }
- --this.count;
+ --this.count;
- if (list.isEmpty()) {
- this.entitiesBySection[sectionIndex] = null;
- this.nonEmptyBitset[sectionIndex >>> 6] ^= (1L << (sectionIndex & (Long.SIZE - 1)));
- }
- } finally {
- this.listLock.unlockWrite(id);
+ if (list.isEmpty()) {
+ this.entitiesBySection[sectionIndex] = null;
+ this.nonEmptyBitset[sectionIndex >>> 6] ^= (1L << (sectionIndex & (Long.SIZE - 1)));
}
}
public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
- final long id = this.listLock.readLock();
- try {
- if (this.count == 0) {
- return;
- }
-
- final int minSection = this.manager.minSection;
- final int maxSection = this.manager.maxSection;
+ if (this.count == 0) {
+ return;
+ }
- final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
- final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
+ final int minSection = this.manager.minSection;
+ final int maxSection = this.manager.maxSection;
- final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
- for (int section = min; section <= max; ++section) {
- final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
+ final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
- if (list == null) {
- continue;
- }
+ for (int section = min; section <= max; ++section) {
+ final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
- final Entity[] storage = list.storage;
+ if (list == null) {
+ continue;
+ }
- for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
- final Entity entity = storage[i];
+ final Entity[] storage = list.storage;
- if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
- continue;
- }
+ for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
+ final Entity entity = storage[i];
- if (predicate != null && !predicate.test(entity)) {
- continue;
- }
+ if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
+ continue;
+ }
- into.add(entity);
+ if (predicate != null && !predicate.test(entity)) {
+ continue;
}
+
+ into.add(entity);
}
- } finally {
- this.listLock.unlockRead(id);
}
}
public void getEntitiesWithEnderDragonParts(final Entity except, final AABB box, final List<Entity> into,
final Predicate<? super Entity> predicate) {
- final long id = this.listLock.readLock();
- try {
- if (this.count == 0) {
- return;
- }
-
- final int minSection = this.manager.minSection;
- final int maxSection = this.manager.maxSection;
+ if (this.count == 0) {
+ return;
+ }
- final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
- final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
+ final int minSection = this.manager.minSection;
+ final int maxSection = this.manager.maxSection;
- final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
- for (int section = min; section <= max; ++section) {
- final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
+ final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
- if (list == null) {
- continue;
- }
+ for (int section = min; section <= max; ++section) {
+ final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
- final Entity[] storage = list.storage;
+ if (list == null) {
+ continue;
+ }
- for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
- final Entity entity = storage[i];
+ final Entity[] storage = list.storage;
- if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
- continue;
- }
+ for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
+ final Entity entity = storage[i];
- if (predicate == null || predicate.test(entity)) {
- into.add(entity);
- } // else: continue to test the ender dragon parts
+ if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
+ continue;
+ }
- if (entity instanceof EnderDragon) {
- for (final EnderDragonPart part : ((EnderDragon) entity).subEntities) {
- if (part == except || !part.getBoundingBox().intersects(box)) {
- continue;
- }
+ if (predicate == null || predicate.test(entity)) {
+ into.add(entity);
+ } // else: continue to test the ender dragon parts
- if (predicate != null && !predicate.test(part)) {
- continue;
- }
+ if (entity instanceof EnderDragon) {
+ for (final EnderDragonPart part : ((EnderDragon) entity).subEntities) {
+ if (part == except || !part.getBoundingBox().intersects(box)) {
+ continue;
+ }
- into.add(part);
+ if (predicate != null && !predicate.test(part)) {
+ continue;
}
+
+ into.add(part);
}
}
}
- } finally {
- this.listLock.unlockRead(id);
}
}
public void getEntitiesWithEnderDragonParts(final Entity except, final Class<?> clazz, final AABB box, final List<Entity> into,
final Predicate<? super Entity> predicate) {
- final long id = this.listLock.readLock();
- try {
- if (this.count == 0) {
- return;
- }
+ if (this.count == 0) {
+ return;
+ }
- final int minSection = this.manager.minSection;
- final int maxSection = this.manager.maxSection;
+ final int minSection = this.manager.minSection;
+ final int maxSection = this.manager.maxSection;
- final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
- final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
- final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
+ final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
- for (int section = min; section <= max; ++section) {
- final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
+ for (int section = min; section <= max; ++section) {
+ final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
- if (list == null) {
- continue;
- }
-
- final Entity[] storage = list.storage;
+ if (list == null) {
+ continue;
+ }
- for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
- final Entity entity = storage[i];
+ final Entity[] storage = list.storage;
- if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
- continue;
- }
+ for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
+ final Entity entity = storage[i];
- if (predicate == null || predicate.test(entity)) {
- into.add(entity);
- } // else: continue to test the ender dragon parts
+ if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
+ continue;
+ }
- if (entity instanceof EnderDragon) {
- for (final EnderDragonPart part : ((EnderDragon) entity).subEntities) {
- if (part == except || !part.getBoundingBox().intersects(box) || !clazz.isInstance(part)) {
- continue;
- }
+ if (predicate == null || predicate.test(entity)) {
+ into.add(entity);
+ } // else: continue to test the ender dragon parts
- if (predicate != null && !predicate.test(part)) {
- continue;
- }
+ if (entity instanceof EnderDragon) {
+ for (final EnderDragonPart part : ((EnderDragon) entity).subEntities) {
+ if (part == except || !part.getBoundingBox().intersects(box) || !clazz.isInstance(part)) {
+ continue;
+ }
- into.add(part);
+ if (predicate != null && !predicate.test(part)) {
+ continue;
}
+
+ into.add(part);
}
}
}
- } finally {
- this.listLock.unlockRead(id);
}
}
public <T extends Entity> void getEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
final Predicate<? super T> predicate) {
- final long id = this.listLock.readLock();
- try {
- if (this.count == 0) {
- return;
- }
-
- final int minSection = this.manager.minSection;
- final int maxSection = this.manager.maxSection;
+ if (this.count == 0) {
+ return;
+ }
- final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
- final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
+ final int minSection = this.manager.minSection;
+ final int maxSection = this.manager.maxSection;
- final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
- for (int section = min; section <= max; ++section) {
- final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
+ final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
- if (list == null) {
- continue;
- }
+ for (int section = min; section <= max; ++section) {
+ final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
- final Entity[] storage = list.storage;
+ if (list == null) {
+ continue;
+ }
- for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
- final Entity entity = storage[i];
+ final Entity[] storage = list.storage;
- if (entity == null || (type != null && entity.getType() != type) || !entity.getBoundingBox().intersects(box)) {
- continue;
- }
+ for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
+ final Entity entity = storage[i];
- if (predicate != null && !predicate.test((T) entity)) {
- continue;
- }
+ if (entity == null || (type != null && entity.getType() != type) || !entity.getBoundingBox().intersects(box)) {
+ continue;
+ }
- into.add((T) entity);
+ if (predicate != null && !predicate.test((T) entity)) {
+ continue;
}
+
+ into.add((T) entity);
}
- } finally {
- this.listLock.unlockRead(id);
}
}
}