mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-23 17:09:29 +00:00
Updated Upstream (Hearse)
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
- Disabling the UseItemOnPacket Too Far check.
|
- Disabling the UseItemOnPacket Too Far check.
|
||||||
- Update all dependencies to the latest.
|
- Update all dependencies to the latest.
|
||||||
- Parallel entity ticking(Half of async)(In alpha)
|
- Parallel entity ticking(Half of async)(In alpha)
|
||||||
|
- Parallel world ticking
|
||||||
- Some Purpur patches.
|
- Some Purpur patches.
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
@@ -64,4 +65,4 @@ Credits:
|
|||||||
- [Petal](https://github.com/Bloom-host/Petal)
|
- [Petal](https://github.com/Bloom-host/Petal)
|
||||||
- [Carpet Fixes](https://github.com/fxmorin/carpet-fixes)
|
- [Carpet Fixes](https://github.com/fxmorin/carpet-fixes)
|
||||||
- [VMP](https://github.com/RelativityMC/VMP-fabric)
|
- [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
4531
patches/api/0012-Hearse-I-am-an-idiot.patch
Normal file
4531
patches/api/0012-Hearse-I-am-an-idiot.patch
Normal file
File diff suppressed because it is too large
Load Diff
1839
patches/server/0041-Hearse-Change-paper-s-code.patch
Normal file
1839
patches/server/0041-Hearse-Change-paper-s-code.patch
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
203
patches/server/0042-Hearse-Pathfiner-changes.patch
Normal file
203
patches/server/0042-Hearse-Pathfiner-changes.patch
Normal 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) {
|
||||||
1047
patches/server/0043-Hearse-MC-code-changes.patch
Normal file
1047
patches/server/0043-Hearse-MC-code-changes.patch
Normal file
File diff suppressed because it is too large
Load Diff
386
patches/server/0044-Hearse-MC-code-changes-2.patch
Normal file
386
patches/server/0044-Hearse-MC-code-changes-2.patch
Normal 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();
|
||||||
|
}
|
||||||
394
patches/server/0045-Hearse-Add-base-codes.patch
Normal file
394
patches/server/0045-Hearse-Add-base-codes.patch
Normal 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
|
||||||
315
patches/server/0046-Hearse-Update-codes.patch
Normal file
315
patches/server/0046-Hearse-Update-codes.patch
Normal 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
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
35
patches/server/0050-Hearse-Fix-an-UOE-in-GoalSelector.patch
Normal file
35
patches/server/0050-Hearse-Fix-an-UOE-in-GoalSelector.patch
Normal 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
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
50
patches/server/0052-Hearse-Run-tasks-when-tick-start.patch
Normal file
50
patches/server/0052-Hearse-Run-tasks-when-tick-start.patch
Normal 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()));
|
||||||
71
patches/server/0053-Hearse-Adjust-some-locks.patch
Normal file
71
patches/server/0053-Hearse-Adjust-some-locks.patch
Normal 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() {
|
||||||
1008
patches/server/0054-Hearse-Fix-some-concurrent-problems.patch
Normal file
1008
patches/server/0054-Hearse-Fix-some-concurrent-problems.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||||
|
}
|
||||||
3607
patches/server/0056-Hearse-I-am-an-idiot.patch
Normal file
3607
patches/server/0056-Hearse-I-am-an-idiot.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
@@ -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;
|
||||||
113
patches/server/0059-Hearse-Change-some-config-key-name.patch
Normal file
113
patches/server/0059-Hearse-Change-some-config-key-name.patch
Normal 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;
|
||||||
302
patches/server/0060-Hearse-Add-worker-command.patch
Normal file
302
patches/server/0060-Hearse-Add-worker-command.patch
Normal 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);
|
||||||
187
patches/server/0061-Hearse-Fix-some-hearse-bugs.patch
Normal file
187
patches/server/0061-Hearse-Fix-some-hearse-bugs.patch
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
223
patches/server/0066-Hearse-Parallel-world-ticking.patch
Normal file
223
patches/server/0066-Hearse-Parallel-world-ticking.patch
Normal 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
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
45
patches/server/0069-Hearse-Fix-some-NPE-errors.patch
Normal file
45
patches/server/0069-Hearse-Fix-some-NPE-errors.patch
Normal 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;
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user