mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-25 09:59:15 +00:00
Hearse: Async entity ai & traveling
This commit is contained in:
@@ -63,3 +63,4 @@ Credits:
|
||||
- [Petal](https://github.com/Bloom-host/Petal)
|
||||
- [Carpet Fixes](https://github.com/fxmorin/carpet-fixes)
|
||||
- [VMP](https://github.com/RelativityMC/VMP-fabric)
|
||||
- [Hearse](https://github.com/NaturalCodeClub/Hearse)
|
||||
|
||||
730
patches/server/0037-Hearse-Async-entity-traveling.patch
Normal file
730
patches/server/0037-Hearse-Async-entity-traveling.patch
Normal file
@@ -0,0 +1,730 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BuildTools <unconfigured@null.spigotmc.org>
|
||||
Date: Wed, 4 Jan 2023 11:35:50 +0800
|
||||
Subject: [PATCH] Hearse: Async entity traveling
|
||||
|
||||
Original license:
|
||||
Original project: https://github.com/NaturalCodeClub/Hearse
|
||||
|
||||
diff --git a/src/main/java/co/m2ek4u/aoame/AnotherTickThread.java b/src/main/java/co/m2ek4u/aoame/AnotherTickThread.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d5fe52beb25e7a95549cdf0ae19edf6029f10642
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/co/m2ek4u/aoame/AnotherTickThread.java
|
||||
@@ -0,0 +1,13 @@
|
||||
+package co.m2ek4u.aoame;
|
||||
+
|
||||
+import io.papermc.paper.util.TickThread;
|
||||
+
|
||||
+public class AnotherTickThread extends TickThread {
|
||||
+ public AnotherTickThread(String name) {
|
||||
+ super(name);
|
||||
+ }
|
||||
+
|
||||
+ public AnotherTickThread(Runnable run, String name) {
|
||||
+ super(run, name);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/co/m2ek4u/aoame/CallbackExecutor.java b/src/main/java/co/m2ek4u/aoame/CallbackExecutor.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b861405a7626ba8fa677c455bf6507253b33c157
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/co/m2ek4u/aoame/CallbackExecutor.java
|
||||
@@ -0,0 +1,99 @@
|
||||
+package co.m2ek4u.aoame;
|
||||
+
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+import java.util.Queue;
|
||||
+import java.util.concurrent.*;
|
||||
+import java.util.concurrent.atomic.AtomicBoolean;
|
||||
+import java.util.concurrent.locks.LockSupport;
|
||||
+
|
||||
+public class CallbackExecutor extends ThreadPoolExecutor {
|
||||
+ private final AtomicBoolean isSubmittingStarted = new AtomicBoolean(false);
|
||||
+ private final Queue<TaskEntry> submittedTasks = new ConcurrentLinkedDeque<>();
|
||||
+
|
||||
+ public CallbackExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue) {
|
||||
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
|
||||
+ }
|
||||
+
|
||||
+ public CallbackExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull ThreadFactory threadFactory) {
|
||||
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
|
||||
+ }
|
||||
+
|
||||
+ public CallbackExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue<Runnable> workQueue, @NotNull RejectedExecutionHandler handler) {
|
||||
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
|
||||
+ }
|
||||
+
|
||||
+ public CallbackExecutor(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 void startSubmitting(){
|
||||
+ if (this.isSubmittingStarted.get()){
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ this.isSubmittingStarted.set(true);
|
||||
+ }
|
||||
+
|
||||
+ public void awaitSubmittingEnd(){
|
||||
+ while (this.isSubmittingStarted.get()){
|
||||
+ LockSupport.parkNanos(this,1);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void executeWithCallBack(Runnable command,Runnable callBack){
|
||||
+ if (this.isSubmittingStarted.get()){
|
||||
+ TaskEntry newTask = new TaskEntry(command,callBack);
|
||||
+ this.execute(newTask::runMainTask);
|
||||
+ this.submittedTasks.add(newTask);
|
||||
+ return;
|
||||
+ }
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+
|
||||
+ public boolean isSubmittingStarted(){
|
||||
+ return this.isSubmittingStarted.get();
|
||||
+ }
|
||||
+
|
||||
+ public void stopSubmitting(){
|
||||
+ if (!this.isSubmittingStarted.get()){
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ this.isSubmittingStarted.set(false);
|
||||
+ TaskEntry task;
|
||||
+ while ((task = this.submittedTasks.poll())!=null){
|
||||
+ while (!task.runSubTask()){
|
||||
+ LockSupport.parkNanos(this,1);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static class TaskEntry{
|
||||
+ private final Runnable mainTask;
|
||||
+ private final Runnable subTask;
|
||||
+ private volatile boolean mainTaskFinished = false;
|
||||
+
|
||||
+ public TaskEntry(Runnable mainTask,Runnable subTask){
|
||||
+ this.mainTask = mainTask;
|
||||
+ this.subTask = subTask;
|
||||
+ }
|
||||
+
|
||||
+ public void runMainTask(){
|
||||
+ try {
|
||||
+ this.mainTask.run();
|
||||
+ }finally {
|
||||
+ this.mainTaskFinished = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public boolean runSubTask(){
|
||||
+ if (!this.mainTaskFinished){
|
||||
+ return false;
|
||||
+ }
|
||||
+ try {
|
||||
+ this.subTask.run();
|
||||
+ }catch (Exception e){
|
||||
+ e.printStackTrace();
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java b/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java
|
||||
index 0133ea6feb1ab88f021f66855669f58367e7420b..b128433d2888a98bce55052e821626c0478748dd 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.destroystokyo.paper.util.maplist;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
+import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
+import it.unimi.dsi.fastutil.objects.ObjectLists;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
@@ -12,117 +15,42 @@ import java.util.NoSuchElementException;
|
||||
*/
|
||||
public final class EntityList implements Iterable<Entity> {
|
||||
|
||||
- protected final Int2IntOpenHashMap entityToIndex = new Int2IntOpenHashMap(2, 0.8f);
|
||||
- {
|
||||
- this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE);
|
||||
- }
|
||||
-
|
||||
- protected static final Entity[] EMPTY_LIST = new Entity[0];
|
||||
-
|
||||
- protected Entity[] entities = EMPTY_LIST;
|
||||
- protected int count;
|
||||
+ private final ObjectList<Entity> objectList = ObjectLists.synchronize(new ObjectArrayList<>());
|
||||
|
||||
public int size() {
|
||||
- return this.count;
|
||||
+ return this.objectList.size();
|
||||
}
|
||||
|
||||
public boolean contains(final Entity entity) {
|
||||
- return this.entityToIndex.containsKey(entity.getId());
|
||||
+ return this.objectList.contains(entity);
|
||||
}
|
||||
|
||||
public boolean remove(final Entity entity) {
|
||||
- final int index = this.entityToIndex.remove(entity.getId());
|
||||
- if (index == Integer.MIN_VALUE) {
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- // move the entity at the end to this index
|
||||
- final int endIndex = --this.count;
|
||||
- final Entity end = this.entities[endIndex];
|
||||
- if (index != endIndex) {
|
||||
- // not empty after this call
|
||||
- this.entityToIndex.put(end.getId(), index); // update index
|
||||
- }
|
||||
- this.entities[index] = end;
|
||||
- this.entities[endIndex] = null;
|
||||
-
|
||||
- return true;
|
||||
+ return this.objectList.remove(entity);
|
||||
}
|
||||
|
||||
public boolean add(final Entity entity) {
|
||||
- final int count = this.count;
|
||||
- final int currIndex = this.entityToIndex.putIfAbsent(entity.getId(), count);
|
||||
-
|
||||
- if (currIndex != Integer.MIN_VALUE) {
|
||||
- return false; // already in this list
|
||||
- }
|
||||
-
|
||||
- Entity[] list = this.entities;
|
||||
-
|
||||
- if (list.length == count) {
|
||||
- // resize required
|
||||
- list = this.entities = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative
|
||||
- }
|
||||
-
|
||||
- list[count] = entity;
|
||||
- this.count = count + 1;
|
||||
-
|
||||
- return true;
|
||||
+ return this.objectList.add(entity);
|
||||
}
|
||||
|
||||
public Entity getChecked(final int index) {
|
||||
- if (index < 0 || index >= this.count) {
|
||||
- throw new IndexOutOfBoundsException("Index: " + index + " is out of bounds, size: " + this.count);
|
||||
- }
|
||||
- return this.entities[index];
|
||||
+ return this.objectList.get(index);
|
||||
}
|
||||
|
||||
public Entity getUnchecked(final int index) {
|
||||
- return this.entities[index];
|
||||
+ return this.objectList.get(index);
|
||||
}
|
||||
|
||||
public Entity[] getRawData() {
|
||||
- return this.entities;
|
||||
+ return this.objectList.toArray(Entity[]::new);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
- this.entityToIndex.clear();
|
||||
- Arrays.fill(this.entities, 0, this.count, null);
|
||||
- this.count = 0;
|
||||
+ this.objectList.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entity> iterator() {
|
||||
- return new Iterator<Entity>() {
|
||||
-
|
||||
- Entity lastRet;
|
||||
- int current;
|
||||
-
|
||||
- @Override
|
||||
- public boolean hasNext() {
|
||||
- return this.current < EntityList.this.count;
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public Entity next() {
|
||||
- if (this.current >= EntityList.this.count) {
|
||||
- throw new NoSuchElementException();
|
||||
- }
|
||||
- return this.lastRet = EntityList.this.entities[this.current++];
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public void remove() {
|
||||
- final Entity lastRet = this.lastRet;
|
||||
-
|
||||
- if (lastRet == null) {
|
||||
- throw new IllegalStateException();
|
||||
- }
|
||||
- this.lastRet = null;
|
||||
-
|
||||
- EntityList.this.remove(lastRet);
|
||||
- --this.current;
|
||||
- }
|
||||
- };
|
||||
+ return this.objectList.iterator();
|
||||
}
|
||||
}
|
||||
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 61c170555c8854b102c640b0b6a615f9f732edbf..ec90ff5c2581706180498b74dbbf960d52d47209 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
|
||||
@@ -6,8 +6,14 @@ import io.papermc.paper.util.CoordinateUtils;
|
||||
import io.papermc.paper.util.TickThread;
|
||||
import io.papermc.paper.util.WorldUtil;
|
||||
import io.papermc.paper.world.ChunkEntitySlices;
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
|
||||
+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.Object2ReferenceMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2ReferenceMaps;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import io.papermc.paper.chunk.system.ChunkSystem;
|
||||
@@ -26,11 +32,8 @@ import net.minecraft.world.phys.AABB;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
-import java.util.ArrayList;
|
||||
-import java.util.Iterator;
|
||||
-import java.util.List;
|
||||
-import java.util.NoSuchElementException;
|
||||
-import java.util.UUID;
|
||||
+
|
||||
+import java.util.*;
|
||||
import java.util.concurrent.locks.StampedLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
@@ -46,15 +49,15 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
public final ServerLevel world;
|
||||
|
||||
private final StampedLock stateLock = new StampedLock();
|
||||
- protected final Long2ObjectOpenHashMap<ChunkSlicesRegion> regions = new Long2ObjectOpenHashMap<>(128, 0.5f);
|
||||
+ protected final Long2ObjectMap<ChunkSlicesRegion> regions = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>(128, 0.5f));
|
||||
|
||||
private final int minSection; // inclusive
|
||||
private final int maxSection; // inclusive
|
||||
private final LevelCallback<Entity> worldCallback;
|
||||
|
||||
private final StampedLock entityByLock = new StampedLock();
|
||||
- private final Int2ReferenceOpenHashMap<Entity> entityById = new Int2ReferenceOpenHashMap<>();
|
||||
- private final Object2ReferenceOpenHashMap<UUID, Entity> entityByUUID = new Object2ReferenceOpenHashMap<>();
|
||||
+ private final Map<Integer,Entity> entityById = Int2ReferenceMaps.synchronize(new Int2ReferenceOpenHashMap<>());
|
||||
+ private final Object2ReferenceMap<UUID, Entity> entityByUUID = Object2ReferenceMaps.synchronize(new Object2ReferenceOpenHashMap<>());
|
||||
private final EntityList accessibleEntities = new EntityList();
|
||||
|
||||
public EntityLookup(final ServerLevel world, final LevelCallback<Entity> worldCallback) {
|
||||
@@ -208,8 +211,8 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
public void get(final AABB box, final Consumer<Entity> action) {
|
||||
List<Entity> entities = new ArrayList<>();
|
||||
this.getEntitiesWithoutDragonParts(null, box, entities, null);
|
||||
- for (int i = 0, len = entities.size(); i < len; ++i) {
|
||||
- action.accept(entities.get(i));
|
||||
+ for (Entity entity : entities) {
|
||||
+ action.accept(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,8 +220,8 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
public <U extends Entity> void get(final EntityTypeTest<Entity, U> filter, final AABB box, final AbortableIterationConsumer<U> action) {
|
||||
List<Entity> entities = new ArrayList<>();
|
||||
this.getEntitiesWithoutDragonParts(null, box, entities, null);
|
||||
- for (int i = 0, len = entities.size(); i < len; ++i) {
|
||||
- final U casted = filter.tryCast(entities.get(i));
|
||||
+ for (Entity entity : entities) {
|
||||
+ final U casted = filter.tryCast(entity);
|
||||
if (casted != null && action.accept(casted).shouldAbort()) {
|
||||
break;
|
||||
}
|
||||
@@ -231,14 +234,14 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
|
||||
if (entity.updatingSectionStatus) {
|
||||
// recursive status update
|
||||
- LOGGER.error("Cannot recursively update entity chunk status for entity " + entity, new Throwable());
|
||||
+ LOGGER.warn("Cannot recursively update entity chunk status for entity " + entity);
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean entityStatusUpdateBefore = slices == null ? false : slices.startPreventingStatusUpdates();
|
||||
|
||||
if (entityStatusUpdateBefore) {
|
||||
- LOGGER.error("Cannot update chunk status for entity " + entity + " since entity chunk (" + slices.chunkX + "," + slices.chunkZ + ") is receiving update", new Throwable());
|
||||
+ LOGGER.warn("Cannot update chunk status for entity " + entity + " since entity chunk (" + slices.chunkX + "," + slices.chunkZ + ") is receiving update");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -347,7 +350,7 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
}
|
||||
|
||||
if (entity.updatingSectionStatus) {
|
||||
- LOGGER.warn("Entity " + entity + " is currently prevented from being added/removed to world since it is processing section status updates", new Throwable());
|
||||
+ LOGGER.warn("Entity " + entity + " is currently prevented from being added/removed to world since it is processing section status updates");
|
||||
return false;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/CachedLists.java b/src/main/java/io/papermc/paper/util/CachedLists.java
|
||||
index e08f4e39db4ee3fed62e37364d17dcc5c5683504..22a5470862acfa470c9acd97c96fea29aede0b68 100644
|
||||
--- a/src/main/java/io/papermc/paper/util/CachedLists.java
|
||||
+++ b/src/main/java/io/papermc/paper/util/CachedLists.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.papermc.paper.util;
|
||||
|
||||
+import com.google.common.collect.Lists;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -8,50 +9,18 @@ import java.util.List;
|
||||
|
||||
public final class CachedLists {
|
||||
|
||||
- // Paper start - optimise collisions
|
||||
- static final UnsafeList<AABB> TEMP_COLLISION_LIST = new UnsafeList<>(1024);
|
||||
- static boolean tempCollisionListInUse;
|
||||
-
|
||||
- public static UnsafeList<AABB> getTempCollisionList() {
|
||||
- if (!Bukkit.isPrimaryThread() || tempCollisionListInUse) {
|
||||
- return new UnsafeList<>(16);
|
||||
- }
|
||||
- tempCollisionListInUse = true;
|
||||
- return TEMP_COLLISION_LIST;
|
||||
- }
|
||||
-
|
||||
- public static void returnTempCollisionList(List<AABB> list) {
|
||||
- if (list != TEMP_COLLISION_LIST) {
|
||||
- return;
|
||||
- }
|
||||
- ((UnsafeList)list).setSize(0);
|
||||
- tempCollisionListInUse = false;
|
||||
+ public static List<AABB> getTempCollisionList() {
|
||||
+ return Lists.newCopyOnWriteArrayList();
|
||||
}
|
||||
|
||||
- static final UnsafeList<Entity> TEMP_GET_ENTITIES_LIST = new UnsafeList<>(1024);
|
||||
- static boolean tempGetEntitiesListInUse;
|
||||
+ public static void returnTempCollisionList(List<AABB> list) {}
|
||||
|
||||
- public static UnsafeList<Entity> getTempGetEntitiesList() {
|
||||
- if (!Bukkit.isPrimaryThread() || tempGetEntitiesListInUse) {
|
||||
- return new UnsafeList<>(16);
|
||||
- }
|
||||
- tempGetEntitiesListInUse = true;
|
||||
- return TEMP_GET_ENTITIES_LIST;
|
||||
+ public static List<Entity> getTempGetEntitiesList() {
|
||||
+ return Lists.newCopyOnWriteArrayList();
|
||||
}
|
||||
|
||||
- public static void returnTempGetEntitiesList(List<Entity> list) {
|
||||
- if (list != TEMP_GET_ENTITIES_LIST) {
|
||||
- return;
|
||||
- }
|
||||
- ((UnsafeList)list).setSize(0);
|
||||
- tempGetEntitiesListInUse = false;
|
||||
- }
|
||||
+ public static void returnTempGetEntitiesList(List<Entity> list) {}
|
||||
// Paper end - optimise collisions
|
||||
|
||||
- public static void reset() {
|
||||
- // Paper start - optimise collisions
|
||||
- TEMP_COLLISION_LIST.completeReset();
|
||||
- TEMP_GET_ENTITIES_LIST.completeReset();
|
||||
- // Paper end - optimise collisions
|
||||
- }
|
||||
+ public static void reset() {}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 75daffc4eaa831708f1ccfa5370ddf1871998033..6eea6430c6fe9174979bf390c008bdedc4c2a51b 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
+import co.m2ek4u.aoame.AnotherTickThread;
|
||||
+import co.m2ek4u.aoame.CallbackExecutor;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import co.aikar.timings.Timings;
|
||||
@@ -41,9 +43,8 @@ import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
-import java.util.concurrent.CompletableFuture;
|
||||
-import java.util.concurrent.Executor;
|
||||
-import java.util.concurrent.RejectedExecutionException;
|
||||
+import java.util.concurrent.*;
|
||||
+import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
@@ -284,6 +285,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
protected WorldData worldData;
|
||||
private volatile boolean isSaving;
|
||||
|
||||
+ private final AtomicInteger threadId = new AtomicInteger();
|
||||
+ public final CallbackExecutor asyncExecutor = new CallbackExecutor(
|
||||
+ Runtime.getRuntime().availableProcessors(),
|
||||
+ Runtime.getRuntime().availableProcessors(),
|
||||
+ 50,
|
||||
+ TimeUnit.MILLISECONDS,
|
||||
+ new LinkedBlockingQueue<>(),
|
||||
+ task -> {
|
||||
+ AnotherTickThread worker = new AnotherTickThread(task,"Entity-Async-Worker # "+threadId.getAndIncrement());
|
||||
+ worker.setDaemon(true);
|
||||
+ return worker;
|
||||
+ }
|
||||
+ );
|
||||
+
|
||||
// CraftBukkit start
|
||||
public final WorldLoader.DataLoadContext worldLoader;
|
||||
public org.bukkit.craftbukkit.CraftServer server;
|
||||
@@ -1333,17 +1348,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
} else {
|
||||
boolean ret = false; // Paper - force execution of all worlds, do not just bias the first
|
||||
if (this.haveTime()) {
|
||||
- Iterator iterator = this.getAllLevels().iterator();
|
||||
-
|
||||
- while (iterator.hasNext()) {
|
||||
- ServerLevel worldserver = (ServerLevel) iterator.next();
|
||||
-
|
||||
+ for (ServerLevel worldserver : this.getAllLevels()) {
|
||||
if (worldserver.getChunkSource().pollTask()) {
|
||||
ret = true; // Paper - force execution of all worlds, do not just bias the first
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
||||
return ret; // Paper - force execution of all worlds, do not just bias the first
|
||||
}
|
||||
}
|
||||
@@ -1393,6 +1403,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public void onServerExit() {}
|
||||
|
||||
public void tickServer(BooleanSupplier shouldKeepTicking) {
|
||||
+ if (this.asyncExecutor.isSubmittingStarted()) {
|
||||
+ this.asyncExecutor.stopSubmitting();
|
||||
+ }
|
||||
co.aikar.timings.TimingsManager.FULL_SERVER_TICK.startTiming(); // Paper
|
||||
long i = Util.getNanos();
|
||||
|
||||
@@ -1406,6 +1419,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper
|
||||
|
||||
++this.tickCount;
|
||||
+ this.asyncExecutor.startSubmitting();
|
||||
this.tickChildren(shouldKeepTicking);
|
||||
if (i - this.lastServerStatus >= 5000000000L) {
|
||||
this.lastServerStatus = i;
|
||||
@@ -1522,11 +1536,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
MinecraftTimings.timeUpdateTimer.stopTiming(); // Spigot // Paper
|
||||
|
||||
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
|
||||
+ // Paper - move down
|
||||
+ 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(() -> {
|
||||
@@ -1557,7 +1570,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
try {
|
||||
crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
|
||||
} catch (Throwable t) {
|
||||
- if (throwable instanceof ThreadDeath) { throw (ThreadDeath)throwable; } // Paper
|
||||
+ if (throwable instanceof ThreadDeath) {
|
||||
+ throw (ThreadDeath) throwable;
|
||||
+ } // Paper
|
||||
throw new RuntimeException("Error generating crash report", t);
|
||||
}
|
||||
// Spigot End
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 53198ebfa30273c5ddc1bb4324f5174ff99f688d..818d607e1b4b52475b2056789c17a7b0cb9ffbe6 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraft.server.level;
|
||||
|
||||
+import co.m2ek4u.aoame.AnotherTickThread;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import co.aikar.timings.TimingHistory; // Paper
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -269,7 +270,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 && !(Thread.currentThread() instanceof AnotherTickThread)) {
|
||||
this.getChunkSource().mainThreadProcessor.execute(() -> {
|
||||
this.loadChunksForMoveAsync(axisalignedbb, priority, onLoad);
|
||||
});
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 120c0804010fd5b38a5f806ca580962ff8b47339..2f2e67b922351ca10d32d807db6c92dc9146f0c0 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -44,6 +44,7 @@ import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -3420,52 +3421,38 @@ public abstract class LivingEntity extends Entity {
|
||||
this.updateFallFlying();
|
||||
AABB axisalignedbb = this.getBoundingBox();
|
||||
|
||||
- // SpigotTimings.timerEntityAIMove.startTiming(); // Spigot // Paper
|
||||
- this.travel(new Vec3((double) this.xxa, (double) this.yya, (double) this.zza));
|
||||
- // SpigotTimings.timerEntityAIMove.stopTiming(); // Spigot // Paper
|
||||
- this.level.getProfiler().pop();
|
||||
- this.level.getProfiler().push("freezing");
|
||||
- boolean flag1 = this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES);
|
||||
- int i;
|
||||
+ if (this instanceof net.minecraft.world.entity.player.Player) {
|
||||
+ // SpigotTimings.timerEntityAIMove.startTiming(); // Spigot // Paper
|
||||
+ this.travel(new Vec3((double) this.xxa, (double) this.yya, (double) this.zza));
|
||||
+ // SpigotTimings.timerEntityAIMove.stopTiming(); // Spigot // Paper
|
||||
+ //this.level.getProfiler().pop(); // Purpur
|
||||
+ //this.level.getProfiler().push("freezing"); // Purpur
|
||||
+ boolean flag1 = this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES);
|
||||
+ int i;
|
||||
|
||||
- if (!this.level.isClientSide && !this.isDeadOrDying() && !freezeLocked) { // Paper - Freeze Tick Lock API
|
||||
- i = this.getTicksFrozen();
|
||||
- if (this.isInPowderSnow && this.canFreeze()) {
|
||||
- this.setTicksFrozen(Math.min(this.getTicksRequiredToFreeze(), i + 1));
|
||||
- } else {
|
||||
- this.setTicksFrozen(Math.max(0, i - 2));
|
||||
+ if (!this.level.isClientSide && !this.isDeadOrDying() && !freezeLocked) { // Paper - Freeze Tick Lock API
|
||||
+ i = this.getTicksFrozen();
|
||||
+ if (this.isInPowderSnow && this.canFreeze()) {
|
||||
+ this.setTicksFrozen(Math.min(this.getTicksRequiredToFreeze(), i + 1));
|
||||
+ } else {
|
||||
+ this.setTicksFrozen(Math.max(0, i - 2));
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
-
|
||||
- this.removeFrost();
|
||||
- this.tryAddFrost();
|
||||
- if (!this.level.isClientSide && this.tickCount % 40 == 0 && this.isFullyFrozen() && this.canFreeze()) {
|
||||
- i = flag1 ? 5 : 1;
|
||||
- this.hurt(DamageSource.FREEZE, (float) i);
|
||||
- }
|
||||
|
||||
- this.level.getProfiler().pop();
|
||||
- this.level.getProfiler().push("push");
|
||||
- if (this.autoSpinAttackTicks > 0) {
|
||||
- --this.autoSpinAttackTicks;
|
||||
- this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox());
|
||||
- }
|
||||
+ this.removeFrost();
|
||||
+ this.tryAddFrost();
|
||||
+ if (!this.level.isClientSide && this.tickCount % 40 == 0 && this.isFullyFrozen() && this.canFreeze()) {
|
||||
+ i = flag1 ? 5 : 1;
|
||||
+ this.hurt(DamageSource.FREEZE, (float) i);
|
||||
+ }
|
||||
|
||||
- this.pushEntities();
|
||||
- this.level.getProfiler().pop();
|
||||
- // Paper start
|
||||
- if (((ServerLevel) this.level).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) {
|
||||
- if (this.xo != getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) {
|
||||
- Location from = new Location(this.level.getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO);
|
||||
- Location to = new Location (this.level.getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
|
||||
- io.papermc.paper.event.entity.EntityMoveEvent event = new io.papermc.paper.event.entity.EntityMoveEvent(this.getBukkitLivingEntity(), from, to.clone());
|
||||
- if (!event.callEvent()) {
|
||||
- absMoveTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch());
|
||||
- } else if (!to.equals(event.getTo())) {
|
||||
- absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch());
|
||||
- }
|
||||
+ this.level.getProfiler().pop();
|
||||
+ if (this.autoSpinAttackTicks > 0) {
|
||||
+ --this.autoSpinAttackTicks;
|
||||
+ this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox());
|
||||
}
|
||||
}
|
||||
+ this.pushEntities();
|
||||
// Paper end
|
||||
if (!this.level.isClientSide && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) {
|
||||
this.hurt(DamageSource.DROWN, 1.0F);
|
||||
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/level/levelgen/LegacyRandomSource.java b/src/main/java/net/minecraft/world/level/levelgen/LegacyRandomSource.java
|
||||
index daa03360dd7044f10b20f36023b305dc7e0bb7df..f11cf0c0701247692075da2f2db7602e72ef1ec8 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/LegacyRandomSource.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/LegacyRandomSource.java
|
||||
@@ -19,17 +19,17 @@ public class LegacyRandomSource implements BitRandomSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public RandomSource fork() {
|
||||
+ public synchronized RandomSource fork() {
|
||||
return new LegacyRandomSource(this.nextLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
- public PositionalRandomFactory forkPositional() {
|
||||
+ public synchronized PositionalRandomFactory forkPositional() {
|
||||
return new LegacyRandomSource.LegacyPositionalRandomFactory(this.nextLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void setSeed(long seed) {
|
||||
+ public synchronized void setSeed(long seed) {
|
||||
if (!this.seed.compareAndSet(this.seed.get(), (seed ^ 25214903917L) & 281474976710655L)) {
|
||||
throw ThreadingDetector.makeThreadingException("LegacyRandomSource", (Thread)null);
|
||||
} else {
|
||||
@@ -38,7 +38,7 @@ public class LegacyRandomSource implements BitRandomSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public int next(int bits) {
|
||||
+ public synchronized int next(int bits) {
|
||||
long l = this.seed.get();
|
||||
long m = l * 25214903917L + 11L & 281474976710655L;
|
||||
if (!this.seed.compareAndSet(l, m)) {
|
||||
@@ -49,7 +49,7 @@ public class LegacyRandomSource implements BitRandomSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public double nextGaussian() {
|
||||
+ public synchronized double nextGaussian() {
|
||||
return this.gaussianSource.nextGaussian();
|
||||
}
|
||||
|
||||
686
patches/server/0038-Hearse-Async-entity-ai.patch
Normal file
686
patches/server/0038-Hearse-Async-entity-ai.patch
Normal file
@@ -0,0 +1,686 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BuildTools <unconfigured@null.spigotmc.org>
|
||||
Date: Wed, 4 Jan 2023 11:37:44 +0800
|
||||
Subject: [PATCH] Hearse: Async entity ai
|
||||
|
||||
Original license:
|
||||
Original project: https://github.com/NaturalCodeClub/Hearse
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java b/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java
|
||||
index 0fd814f1d65c111266a2b20f86561839a4cef755..fe4d76875462ac9d408c972b968647af78f2ed14 100644
|
||||
--- a/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java
|
||||
+++ b/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java
|
||||
@@ -94,7 +94,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
return 1.0 - ((double)this.indexMap.size() / (double)this.listSize);
|
||||
}
|
||||
|
||||
- public int createRawIterator() {
|
||||
+ public synchronized int createRawIterator() {
|
||||
if (this.allowSafeIteration()) {
|
||||
++this.iteratorCount;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
}
|
||||
}
|
||||
|
||||
- public int advanceRawIterator(final int index) {
|
||||
+ public synchronized int advanceRawIterator(final int index) {
|
||||
final E[] elements = this.listElements;
|
||||
int ret = index + 1;
|
||||
for (int len = this.listSize; ret < len; ++ret) {
|
||||
@@ -117,7 +117,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
return -1;
|
||||
}
|
||||
|
||||
- public void finishRawIterator() {
|
||||
+ public synchronized void finishRawIterator() {
|
||||
if (this.allowSafeIteration() && --this.iteratorCount == 0) {
|
||||
if (this.getFragFactor() >= this.maxFragFactor) {
|
||||
this.defrag();
|
||||
@@ -125,7 +125,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
}
|
||||
}
|
||||
|
||||
- public boolean remove(final E element) {
|
||||
+ public synchronized boolean remove(final E element) {
|
||||
final int index = this.indexMap.removeInt(element);
|
||||
if (index >= 0) {
|
||||
if (this.firstInvalidIndex < 0 || index < this.firstInvalidIndex) {
|
||||
@@ -144,11 +144,11 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
return false;
|
||||
}
|
||||
|
||||
- public boolean contains(final E element) {
|
||||
+ public synchronized boolean contains(final E element) {
|
||||
return this.indexMap.containsKey(element);
|
||||
}
|
||||
|
||||
- public boolean add(final E element) {
|
||||
+ public synchronized boolean add(final E element) {
|
||||
final int listSize = this.listSize;
|
||||
|
||||
final int previous = this.indexMap.putIfAbsent(element, listSize);
|
||||
@@ -223,30 +223,30 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
//this.check();
|
||||
}
|
||||
|
||||
- public E rawGet(final int index) {
|
||||
+ public synchronized E rawGet(final int index) {
|
||||
return this.listElements[index];
|
||||
}
|
||||
|
||||
- public int size() {
|
||||
+ public synchronized int size() {
|
||||
// always returns the correct amount - listSize can be different
|
||||
return this.indexMap.size();
|
||||
}
|
||||
|
||||
- public IteratorSafeOrderedReferenceSet.Iterator<E> iterator() {
|
||||
+ public synchronized IteratorSafeOrderedReferenceSet.Iterator<E> iterator() {
|
||||
return this.iterator(0);
|
||||
}
|
||||
|
||||
- public IteratorSafeOrderedReferenceSet.Iterator<E> iterator(final int flags) {
|
||||
+ public synchronized IteratorSafeOrderedReferenceSet.Iterator<E> iterator(final int flags) {
|
||||
if (this.allowSafeIteration()) {
|
||||
++this.iteratorCount;
|
||||
}
|
||||
return new BaseIterator<>(this, true, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize);
|
||||
}
|
||||
|
||||
- public java.util.Iterator<E> unsafeIterator() {
|
||||
+ public synchronized java.util.Iterator<E> unsafeIterator() {
|
||||
return this.unsafeIterator(0);
|
||||
}
|
||||
- public java.util.Iterator<E> unsafeIterator(final int flags) {
|
||||
+ public synchronized java.util.Iterator<E> unsafeIterator(final int flags) {
|
||||
return new BaseIterator<>(this, false, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize);
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public boolean hasNext() {
|
||||
+ public synchronized boolean hasNext() {
|
||||
if (this.finished) {
|
||||
return false;
|
||||
}
|
||||
@@ -297,7 +297,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public E next() {
|
||||
+ public synchronized E next() {
|
||||
if (!this.hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
@@ -310,7 +310,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void remove() {
|
||||
+ public synchronized void remove() {
|
||||
final E lastReturned = this.lastReturned;
|
||||
if (lastReturned == null) {
|
||||
throw new IllegalStateException();
|
||||
@@ -320,7 +320,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void finishedIterating() {
|
||||
+ public synchronized void finishedIterating() {
|
||||
if (this.finished || !this.canFinish) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||
index f597d65d56964297eeeed6c7e77703764178fee0..b3bcafc8bafe1e4a1a2b690499b91e5316a604f1 100644
|
||||
--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||
+++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||
@@ -4,6 +4,7 @@ import com.destroystokyo.paper.util.maplist.EntityList;
|
||||
import io.papermc.paper.chunk.system.entity.EntityLookup;
|
||||
import io.papermc.paper.util.TickThread;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
@@ -34,7 +35,7 @@ public final class ChunkEntitySlices {
|
||||
|
||||
protected final EntityCollectionBySection allEntities;
|
||||
protected final EntityCollectionBySection hardCollidingEntities;
|
||||
- protected final Reference2ObjectOpenHashMap<Class<? extends Entity>, EntityCollectionBySection> entitiesByClass;
|
||||
+ protected final Reference2ObjectMap<Class<? extends Entity>, EntityCollectionBySection> entitiesByClass;
|
||||
protected final EntityList entities = new EntityList();
|
||||
|
||||
public ChunkHolder.FullChunkStatus status;
|
||||
@@ -61,7 +62,7 @@ public final class ChunkEntitySlices {
|
||||
|
||||
this.allEntities = new EntityCollectionBySection(this);
|
||||
this.hardCollidingEntities = new EntityCollectionBySection(this);
|
||||
- this.entitiesByClass = new Reference2ObjectOpenHashMap<>();
|
||||
+ this.entitiesByClass = Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>());
|
||||
|
||||
this.status = status;
|
||||
}
|
||||
@@ -209,7 +210,7 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
|
||||
for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
|
||||
- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
|
||||
+ this.entitiesByClass.reference2ObjectEntrySet().iterator(); iterator.hasNext();) {
|
||||
final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
|
||||
|
||||
if (entry.getKey().isInstance(entity)) {
|
||||
@@ -234,7 +235,7 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
|
||||
for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
|
||||
- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
|
||||
+ this.entitiesByClass.reference2ObjectEntrySet().iterator(); iterator.hasNext();) {
|
||||
final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
|
||||
|
||||
if (entry.getKey().isInstance(entity)) {
|
||||
@@ -312,11 +313,11 @@ public final class ChunkEntitySlices {
|
||||
this.storage = (E[])(cap <= 0 ? EMPTY : new Entity[cap]);
|
||||
}
|
||||
|
||||
- public boolean isEmpty() {
|
||||
+ public synchronized boolean isEmpty() {
|
||||
return this.size == 0;
|
||||
}
|
||||
|
||||
- public int size() {
|
||||
+ public synchronized int size() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
@@ -328,7 +329,7 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
}
|
||||
|
||||
- public void add(final E entity) {
|
||||
+ public synchronized void add(final E entity) {
|
||||
final int idx = this.size++;
|
||||
if (idx >= this.storage.length) {
|
||||
this.resize();
|
||||
@@ -338,7 +339,7 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
}
|
||||
|
||||
- public int indexOf(final E entity) {
|
||||
+ public synchronized 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) {
|
||||
@@ -350,7 +351,7 @@ public final class ChunkEntitySlices {
|
||||
return -1;
|
||||
}
|
||||
|
||||
- public boolean remove(final E entity) {
|
||||
+ public synchronized boolean remove(final E entity) {
|
||||
final int idx = this.indexOf(entity);
|
||||
if (idx == -1) {
|
||||
return false;
|
||||
@@ -367,7 +368,7 @@ public final class ChunkEntitySlices {
|
||||
return true;
|
||||
}
|
||||
|
||||
- public boolean has(final E entity) {
|
||||
+ public synchronized boolean has(final E entity) {
|
||||
return this.indexOf(entity) != -1;
|
||||
}
|
||||
}
|
||||
@@ -388,7 +389,7 @@ public final class ChunkEntitySlices {
|
||||
this.entitiesBySection = new BasicEntityList[sectionCount];
|
||||
}
|
||||
|
||||
- public void addEntity(final Entity entity, final int sectionIndex) {
|
||||
+ public synchronized void addEntity(final Entity entity, final int sectionIndex) {
|
||||
BasicEntityList<Entity> list = this.entitiesBySection[sectionIndex];
|
||||
|
||||
if (list != null && list.has(entity)) {
|
||||
@@ -404,7 +405,7 @@ public final class ChunkEntitySlices {
|
||||
++this.count;
|
||||
}
|
||||
|
||||
- public void removeEntity(final Entity entity, final int sectionIndex) {
|
||||
+ public synchronized void removeEntity(final Entity entity, final int sectionIndex) {
|
||||
final BasicEntityList<Entity> list = this.entitiesBySection[sectionIndex];
|
||||
|
||||
if (list == null || !list.remove(entity)) {
|
||||
@@ -419,7 +420,7 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
}
|
||||
|
||||
- public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||
+ public synchronized void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||
if (this.count == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -457,7 +458,7 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
}
|
||||
|
||||
- public void getEntitiesWithEnderDragonParts(final Entity except, final AABB box, final List<Entity> into,
|
||||
+ public synchronized void getEntitiesWithEnderDragonParts(final Entity except, final AABB box, final List<Entity> into,
|
||||
final Predicate<? super Entity> predicate) {
|
||||
if (this.count == 0) {
|
||||
return;
|
||||
@@ -508,7 +509,7 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
}
|
||||
|
||||
- public void getEntitiesWithEnderDragonParts(final Entity except, final Class<?> clazz, final AABB box, final List<Entity> into,
|
||||
+ public synchronized void getEntitiesWithEnderDragonParts(final Entity except, final Class<?> clazz, final AABB box, final List<Entity> into,
|
||||
final Predicate<? super Entity> predicate) {
|
||||
if (this.count == 0) {
|
||||
return;
|
||||
@@ -559,7 +560,7 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
}
|
||||
|
||||
- public <T extends Entity> void getEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
|
||||
+ public synchronized <T extends Entity> void getEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
|
||||
final Predicate<? super T> predicate) {
|
||||
if (this.count == 0) {
|
||||
return;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index d939b1e3bc101e66bc1019cf49d8079665dadfcc..897c9a664806c43a4e7ff444ef69392b9b5cfab6 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -15,6 +15,7 @@ import com.mojang.logging.LogUtils;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
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.Long2ByteMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
|
||||
@@ -25,8 +26,8 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
-import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator;
|
||||
-import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
+import it.unimi.dsi.fastutil.objects.*;
|
||||
+
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Path;
|
||||
@@ -52,6 +53,7 @@ import java.util.function.IntSupplier;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
+
|
||||
import net.minecraft.CrashReport;
|
||||
import net.minecraft.CrashReportCategory;
|
||||
import net.minecraft.ReportedException;
|
||||
@@ -113,7 +115,6 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
|
||||
import org.bukkit.entity.Player;
|
||||
// CraftBukkit end
|
||||
|
||||
-import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
|
||||
|
||||
public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider {
|
||||
|
||||
@@ -153,7 +154,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
private final Queue<Runnable> unloadQueue;
|
||||
int viewDistance;
|
||||
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper
|
||||
- public final ReferenceOpenHashSet<ChunkHolder> needsChangeBroadcasting = new ReferenceOpenHashSet<>();
|
||||
+ public final ReferenceSet<ChunkHolder> needsChangeBroadcasting = ReferenceSets.synchronize(new ReferenceOpenHashSet<>());
|
||||
|
||||
// Paper - rewrite chunk system
|
||||
// Paper start - optimise checkDespawn
|
||||
@@ -295,7 +296,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
// Paper - rewrite chunk system
|
||||
this.tickingGenerated = new AtomicInteger();
|
||||
this.playerMap = new PlayerMap();
|
||||
- this.entityMap = new Int2ObjectOpenHashMap();
|
||||
+ this.entityMap = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap());
|
||||
this.chunkTypeCache = new Long2ByteOpenHashMap();
|
||||
this.chunkSaveCooldowns = new Long2LongOpenHashMap();
|
||||
this.unloadQueue = Queues.newConcurrentLinkedQueue();
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index c6f5d6756fa0e068a462d9c0ded12e0771abba37..788222965a82b21f669a7e7b10c50762968b67c0 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -6,12 +6,7 @@ import com.mojang.datafixers.DataFixer;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
-import java.util.Arrays;
|
||||
-import java.util.Collections;
|
||||
-import java.util.Iterator;
|
||||
-import java.util.List;
|
||||
-import java.util.Objects;
|
||||
-import java.util.Optional;
|
||||
+import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BooleanSupplier;
|
||||
@@ -803,7 +798,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
gameprofilerfiller.popPush("broadcast");
|
||||
this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing
|
||||
if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) {
|
||||
- ReferenceOpenHashSet<ChunkHolder> copy = this.chunkMap.needsChangeBroadcasting.clone();
|
||||
+ 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/util/ClassInstanceMultiMap.java b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
|
||||
index 50a9f33aa31e9273c7c52d4bb2b02f0f884f7ba5..6d94aa3c175345f701ec67175fad3fcde4481041 100644
|
||||
--- a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
|
||||
+++ b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
|
||||
@@ -10,12 +10,14 @@ import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
+import java.util.concurrent.CopyOnWriteArrayList;
|
||||
+import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
|
||||
- private final Map<Class<?>, List<T>> byClass = Maps.newHashMap();
|
||||
+ private final Map<Class<?>, List<T>> byClass = Maps.newConcurrentMap();
|
||||
private final Class<T> baseClass;
|
||||
- private final List<T> allInstances = Lists.newArrayList();
|
||||
+ private final List<T> allInstances = Lists.newCopyOnWriteArrayList();
|
||||
|
||||
public ClassInstanceMultiMap(Class<T> elementType) {
|
||||
this.baseClass = elementType;
|
||||
@@ -58,22 +60,24 @@ public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
|
||||
if (!this.baseClass.isAssignableFrom(type)) {
|
||||
throw new IllegalArgumentException("Don't know how to search for " + type);
|
||||
} else {
|
||||
- List<? extends T> list = this.byClass.computeIfAbsent(type, (typeClass) -> {
|
||||
- return this.allInstances.stream().filter(typeClass::isInstance).collect(Collectors.toList());
|
||||
- });
|
||||
- return Collections.unmodifiableCollection(list);
|
||||
+ List<? extends T> list = this.byClass.computeIfAbsent(type, (typeClass) -> this.allInstances.stream().filter(typeClass::isInstance).collect(toList()));
|
||||
+ return (Collection<S>) Collections.unmodifiableCollection(list);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
- return (Iterator<T>)(this.allInstances.isEmpty() ? Collections.emptyIterator() : Iterators.unmodifiableIterator(this.allInstances.iterator()));
|
||||
+ return this.allInstances.isEmpty() ? Collections.emptyIterator() : Iterators.unmodifiableIterator(this.allInstances.iterator());
|
||||
}
|
||||
|
||||
public List<T> getAllInstances() {
|
||||
return ImmutableList.copyOf(this.allInstances);
|
||||
}
|
||||
|
||||
+ public static <T> Collector<T, ?, List<T>> toList() {
|
||||
+ return Collectors.toCollection(CopyOnWriteArrayList::new);
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public int size() {
|
||||
return this.allInstances.size();
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
index 48746d84f18cc8ee2f57785c65a5659ced454d39..62e82f7e76bcf53da1caf709e5cf3088db840a32 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
@@ -23,6 +23,7 @@ import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
@@ -216,12 +217,14 @@ public abstract class Mob extends LivingEntity {
|
||||
public void inactiveTick() {
|
||||
super.inactiveTick();
|
||||
boolean isThrottled = gg.pufferfish.pufferfish.PufferfishConfig.throttleInactiveGoalSelectorTick && _pufferfish_inactiveTickDisableCounter++ % 20 != 0; // Pufferfish - throttle inactive goal selector ticking
|
||||
- if (this.goalSelector.inactiveTick(this.activatedPriority, true) && !isThrottled) { // Pufferfish - pass activated priroity // Pufferfish - throttle inactive goal selector ticking
|
||||
- this.goalSelector.tick();
|
||||
- }
|
||||
- if (this.targetSelector.inactiveTick(this.activatedPriority, true)) { // Pufferfish - pass activated priority
|
||||
- this.targetSelector.tick();
|
||||
- }
|
||||
+ MinecraftServer.getServer().asyncExecutor.executeWithCallBack(()->{
|
||||
+ if (this.goalSelector.inactiveTick(this.activatedPriority, true) && !isThrottled) { // Pufferfish - pass activated priroity // Pufferfish - throttle inactive goal selector ticking
|
||||
+ this.goalSelector.tick();
|
||||
+ }
|
||||
+ if (this.targetSelector.inactiveTick(this.activatedPriority, true)) { // Pufferfish - pass activated priority
|
||||
+ this.targetSelector.tick();
|
||||
+ }
|
||||
+ },()->{});
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -878,42 +881,32 @@ public abstract class Mob extends LivingEntity {
|
||||
if (i % 10 == 0) this.sensing.tick(); // petal - only refresh line of sight cache every half second
|
||||
this.level.getProfiler().pop();
|
||||
|
||||
- if (i % 2 != 0 && this.tickCount > 1) {
|
||||
- this.level.getProfiler().push("targetSelector");
|
||||
- if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
||||
- this.targetSelector.tickRunningGoals(false);
|
||||
- this.level.getProfiler().pop();
|
||||
- this.level.getProfiler().push("goalSelector");
|
||||
- if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
||||
- this.goalSelector.tickRunningGoals(false);
|
||||
- this.level.getProfiler().pop();
|
||||
- } else {
|
||||
- this.level.getProfiler().push("targetSelector");
|
||||
- if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
||||
- this.targetSelector.tick();
|
||||
- this.level.getProfiler().pop();
|
||||
- this.level.getProfiler().push("goalSelector");
|
||||
- if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
||||
- this.goalSelector.tick();
|
||||
- this.level.getProfiler().pop();
|
||||
- }
|
||||
-
|
||||
- this.level.getProfiler().push("navigation");
|
||||
- this.navigation.tick();
|
||||
- this.level.getProfiler().pop();
|
||||
- this.level.getProfiler().push("mob tick");
|
||||
- this.customServerAiStep();
|
||||
- this.level.getProfiler().pop();
|
||||
- this.level.getProfiler().push("controls");
|
||||
- this.level.getProfiler().push("move");
|
||||
- this.moveControl.tick();
|
||||
- this.level.getProfiler().popPush("look");
|
||||
- this.lookControl.tick();
|
||||
- this.level.getProfiler().popPush("jump");
|
||||
- this.jumpControl.tick();
|
||||
- this.level.getProfiler().pop();
|
||||
- this.level.getProfiler().pop();
|
||||
- this.sendDebugPackets();
|
||||
+ MinecraftServer.getServer().asyncExecutor.executeWithCallBack(() -> {
|
||||
+ if (i % 2 != 0 && this.tickCount > 1) {
|
||||
+ this.level.getProfiler().push("targetSelector");
|
||||
+ if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
||||
+ this.targetSelector.tickRunningGoals(false);
|
||||
+ this.level.getProfiler().pop();
|
||||
+ this.level.getProfiler().push("goalSelector");
|
||||
+ if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
||||
+ this.goalSelector.tickRunningGoals(false);
|
||||
+ this.level.getProfiler().pop();
|
||||
+ } else {
|
||||
+ this.level.getProfiler().push("targetSelector");
|
||||
+ if (this.targetSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
||||
+ this.targetSelector.tick();
|
||||
+ this.level.getProfiler().pop();
|
||||
+ this.level.getProfiler().push("goalSelector");
|
||||
+ if (this.goalSelector.inactiveTick(this.activatedPriority, false)) // Pufferfish - use this to alternate ticking
|
||||
+ this.goalSelector.tick();
|
||||
+ this.level.getProfiler().pop();
|
||||
+ }
|
||||
+ this.navigation.tick();
|
||||
+ this.customServerAiStep();
|
||||
+ this.moveControl.tick();
|
||||
+ this.lookControl.tick();
|
||||
+ this.jumpControl.tick();
|
||||
+ }, this::sendDebugPackets);
|
||||
}
|
||||
|
||||
protected void sendDebugPackets() {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
index 097007c1c25ba55d9916fc820dd1d1149d81f6f4..16eec12db529dd513e0971289a9326652369de58 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
@@ -30,11 +30,11 @@ import org.slf4j.Logger;
|
||||
public class GossipContainer {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final int DISCARD_THRESHOLD = 2;
|
||||
- public final Map<UUID, GossipContainer.EntityGossips> gossips = Maps.newHashMap();
|
||||
+ public final Map<UUID, GossipContainer.EntityGossips> gossips = Maps.newConcurrentMap();
|
||||
|
||||
@VisibleForDebug
|
||||
public Map<UUID, Object2IntMap<GossipType>> getGossipEntries() {
|
||||
- Map<UUID, Object2IntMap<GossipType>> map = Maps.newHashMap();
|
||||
+ Map<UUID, Object2IntMap<GossipType>> map = Maps.newConcurrentMap();
|
||||
this.gossips.keySet().forEach((uuid) -> {
|
||||
GossipContainer.EntityGossips entityGossips = this.gossips.get(uuid);
|
||||
map.put(uuid, entityGossips.entries);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
index a39d038b5198c9244e2225e0fe383f3c96b49a08..948b3ae132dc291551a466a2c7569de3ba632c04 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
@@ -274,16 +274,18 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
if (this.getUnhappyCounter() > 0) {
|
||||
this.setUnhappyCounter(this.getUnhappyCounter() - 1);
|
||||
}
|
||||
- if (this.isEffectiveAi()) {
|
||||
- if (level.spigotConfig.tickInactiveVillagers) {
|
||||
- this.customServerAiStep();
|
||||
- } else {
|
||||
- this.mobTick(true);
|
||||
+ MinecraftServer.getServer().asyncExecutor.executeWithCallBack(()->{
|
||||
+ if (this.isEffectiveAi()) {
|
||||
+ if (level.spigotConfig.tickInactiveVillagers) {
|
||||
+ this.customServerAiStep();
|
||||
+ } else {
|
||||
+ this.mobTick(true);
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
- maybeDecayGossip();
|
||||
+ },()->{
|
||||
+ maybeDecayGossip();
|
||||
+ });
|
||||
// Paper end
|
||||
-
|
||||
super.inactiveTick();
|
||||
}
|
||||
// Spigot End
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/EntityLookup.java b/src/main/java/net/minecraft/world/level/entity/EntityLookup.java
|
||||
index d45d832232be5017dde53816191c2b1830a0da32..f73f78e2f7c6e3eae66f7608a92854b3246e153d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/EntityLookup.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/EntityLookup.java
|
||||
@@ -8,13 +8,15 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||
import net.minecraft.util.AbortableIterationConsumer;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class EntityLookup<T extends EntityAccess> {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
- private final Int2ObjectMap<T> byId = new Int2ObjectLinkedOpenHashMap<>();
|
||||
- private final Map<UUID, T> byUuid = Maps.newHashMap();
|
||||
+ private final Int2ObjectMap<T> byId = Int2ObjectMaps.synchronize(new Int2ObjectLinkedOpenHashMap<>());
|
||||
+ private final Map<UUID, T> byUuid = Maps.newConcurrentMap();
|
||||
|
||||
public <U extends T> void getEntities(EntityTypeTest<T, U> filter, AbortableIterationConsumer<U> consumer) {
|
||||
for(T entityAccess : this.byId.values()) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
index a77985b2dd7137d8eea03909403fc08e89376d73..6bcbbbfc39432076a3d7714ecc2d05d9112d405c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
@@ -4,12 +4,8 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Queues;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mojang.logging.LogUtils;
|
||||
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.longs.*;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
|
||||
-import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
|
||||
-import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
-import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
-import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
@@ -39,15 +35,15 @@ import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
public class PersistentEntitySectionManager<T extends EntityAccess> implements AutoCloseable {
|
||||
|
||||
static final Logger LOGGER = LogUtils.getLogger();
|
||||
- final Set<UUID> knownUuids = Sets.newHashSet();
|
||||
+ final Set<UUID> knownUuids = Sets.newConcurrentHashSet();
|
||||
final LevelCallback<T> callbacks;
|
||||
public final EntityPersistentStorage<T> permanentStorage;
|
||||
private final EntityLookup<T> visibleEntityStorage = new EntityLookup<>();
|
||||
final EntitySectionStorage<T> sectionStorage;
|
||||
private final LevelEntityGetter<T> entityGetter;
|
||||
- private final Long2ObjectMap<Visibility> chunkVisibility = new Long2ObjectOpenHashMap();
|
||||
- private final Long2ObjectMap<PersistentEntitySectionManager.ChunkLoadStatus> chunkLoadStatuses = new Long2ObjectOpenHashMap();
|
||||
- private final LongSet chunksToUnload = new LongOpenHashSet();
|
||||
+ private final Long2ObjectMap<Visibility> chunkVisibility = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap());
|
||||
+ private final Long2ObjectMap<PersistentEntitySectionManager.ChunkLoadStatus> chunkLoadStatuses = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap());
|
||||
+ private final LongSet chunksToUnload = LongSets.synchronize(new LongOpenHashSet());
|
||||
private final Queue<ChunkEntities<T>> loadingInbox = Queues.newConcurrentLinkedQueue();
|
||||
|
||||
public PersistentEntitySectionManager(Class<T> entityClass, LevelCallback<T> handler, EntityPersistentStorage<T> dataAccess) {
|
||||
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 b1c594dc6a6b8a6c737b99272acab9e7dbd0ed63..4aedee56077159aaf613033b688d2be6833f1ad1 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,10 @@ 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 javax.annotation.Nullable;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -16,8 +19,8 @@ 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 List<CollectingNeighborUpdater.NeighborUpdates> addedThisLayer = new ArrayList<>();
|
||||
+ private final Deque<NeighborUpdates> stack = new ConcurrentLinkedDeque<>();
|
||||
+ private final List<CollectingNeighborUpdater.NeighborUpdates> addedThisLayer = new CopyOnWriteArrayList<>();
|
||||
private int count = 0;
|
||||
|
||||
public CollectingNeighborUpdater(Level world, int maxChainDepth) {
|
||||
@@ -26,22 +29,22 @@ 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));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BuildTools <unconfigured@null.spigotmc.org>
|
||||
Date: Wed, 4 Jan 2023 15:19:31 +0800
|
||||
Subject: [PATCH] Hearse: Try to fix some thread problems may happen
|
||||
|
||||
Original license:
|
||||
Original project: https://github.com/NaturalCodeClub/Hearse
|
||||
|
||||
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..c949325dc9b21d8a75ee639210911c61616949c8 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
|
||||
@@ -4,10 +4,8 @@ public class BinaryHeap {
|
||||
private Node[] heap = new Node[128];
|
||||
private int size;
|
||||
|
||||
- public Node insert(Node node) {
|
||||
- if (node.heapIdx >= 0) {
|
||||
- throw new IllegalStateException("OW KNOWS!");
|
||||
- } else {
|
||||
+ public synchronized Node insert(Node node) {
|
||||
+ if (node.heapIdx < 0) {
|
||||
if (this.size == this.heap.length) {
|
||||
Node[] nodes = new Node[this.size << 1];
|
||||
System.arraycopy(this.heap, 0, nodes, 0, this.size);
|
||||
@@ -17,19 +15,19 @@ public class BinaryHeap {
|
||||
this.heap[this.size] = node;
|
||||
node.heapIdx = this.size;
|
||||
this.upHeap(this.size++);
|
||||
- return node;
|
||||
}
|
||||
+ return node;
|
||||
}
|
||||
|
||||
- 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 +39,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 +53,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,7 +64,7 @@ public class BinaryHeap {
|
||||
|
||||
}
|
||||
|
||||
- public int size() {
|
||||
+ public synchronized int size() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
@@ -135,11 +133,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/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) {
|
||||
Reference in New Issue
Block a user