mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2026-01-06 15:51:31 +00:00
8151 lines
300 KiB
Diff
8151 lines
300 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: BuildTools <unconfigured@null.spigotmc.org>
|
|
Date: Wed, 4 Jan 2023 10:55:10 +0800
|
|
Subject: [PATCH] Hearse: Patches
|
|
|
|
Original license:
|
|
Original project: https://github.com/NaturalCodeClub/Hearse
|
|
|
|
1.Add config system
|
|
2.Parallel entity ticking(In alpha)
|
|
3.Some concurrent problems fix
|
|
|
|
diff --git a/src/main/java/co/m2ek4u/hearse/ForkJoinTickThread.java b/src/main/java/co/m2ek4u/hearse/ForkJoinTickThread.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..2f8a2669d6ad8498da7bec9be8ab419b24b83600
|
|
--- /dev/null
|
|
+++ b/src/main/java/co/m2ek4u/hearse/ForkJoinTickThread.java
|
|
@@ -0,0 +1,31 @@
|
|
+package co.m2ek4u.hearse;
|
|
+
|
|
+import it.unimi.dsi.fastutil.objects.ObjectArraySet;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSet;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSets;
|
|
+
|
|
+import java.util.concurrent.ForkJoinPool;
|
|
+import java.util.concurrent.ForkJoinWorkerThread;
|
|
+
|
|
+public class ForkJoinTickThread extends ForkJoinWorkerThread {
|
|
+ private static final ObjectSet<Thread> workerThreads = ObjectSets.synchronize(new ObjectArraySet<>());
|
|
+
|
|
+ public ForkJoinTickThread(ForkJoinPool pool) {
|
|
+ super(pool);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void onStart() {
|
|
+ workerThreads.add(this);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ protected void onTermination(Throwable exception) {
|
|
+ workerThreads.remove(this);
|
|
+ super.onTermination(exception);
|
|
+ }
|
|
+
|
|
+ public static boolean isAnotherForKJoinTickThread(){
|
|
+ return workerThreads.contains(Thread.currentThread());
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/co/m2ek4u/hearse/HearseConfig.java b/src/main/java/co/m2ek4u/hearse/HearseConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..c2760d56ede46632b0225501ca93470871b45853
|
|
--- /dev/null
|
|
+++ b/src/main/java/co/m2ek4u/hearse/HearseConfig.java
|
|
@@ -0,0 +1,45 @@
|
|
+package co.m2ek4u.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 YamlConfiguration configEntry;
|
|
+ private static final File CONFIG_FILE = new File("hearse.yml");
|
|
+
|
|
+ public static void init() {
|
|
+ configEntry = new YamlConfiguration();
|
|
+ try {
|
|
+ configEntry.load(CONFIG_FILE);
|
|
+ } catch (InvalidConfigurationException e) {
|
|
+ e.printStackTrace();
|
|
+ } catch (IOException ignored) {}
|
|
+ configEntry.options().copyDefaults(true);
|
|
+ }
|
|
+
|
|
+ public static void save(){
|
|
+ try {
|
|
+ configEntry.save(CONFIG_FILE);
|
|
+ }catch (Exception e){
|
|
+ e.printStackTrace();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static int getInt(String key,int defaultValue){
|
|
+ configEntry.addDefault(key,defaultValue);
|
|
+ return configEntry.getInt(key);
|
|
+ }
|
|
+
|
|
+ public static boolean getBoolean(String key,boolean defaultValue){
|
|
+ configEntry.addDefault(key,defaultValue);
|
|
+ return configEntry.getBoolean(key);
|
|
+ }
|
|
+
|
|
+ public static String getString(String key,String defaultValue){
|
|
+ configEntry.addDefault(key,defaultValue);
|
|
+ return configEntry.getString(key);
|
|
+ }
|
|
+}
|
|
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..f1043ea3fa8158b1262591abb65e3f9b1c63ba55 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,46 @@ 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 isEmpty(){
|
|
+ return this.objectList.isEmpty();
|
|
}
|
|
|
|
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/PlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java
|
|
index 0b060183429f4c72ec767075538477b4302bbf0d..b8d80be33322504782f309c79ca6f3389e8e77b4 100644
|
|
--- a/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java
|
|
+++ b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java
|
|
@@ -6,10 +6,9 @@ import io.papermc.paper.configuration.GlobalConfiguration;
|
|
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.objects.*;
|
|
+import net.himeki.mcmtfabric.parallelised.fastutil.ConcurrentLongLinkedOpenHashSet;
|
|
import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundSetSimulationDistancePacket;
|
|
@@ -22,10 +21,10 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
|
import org.apache.commons.lang3.mutable.MutableObject;
|
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
|
import org.bukkit.entity.Player;
|
|
-import java.util.ArrayDeque;
|
|
-import java.util.ArrayList;
|
|
-import java.util.List;
|
|
-import java.util.TreeSet;
|
|
+
|
|
+import java.util.*;
|
|
+import java.util.concurrent.ConcurrentLinkedDeque;
|
|
+import java.util.concurrent.ConcurrentSkipListSet;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
public final class PlayerChunkLoader {
|
|
@@ -76,10 +75,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;
|
|
}
|
|
@@ -109,7 +108,7 @@ public final class PlayerChunkLoader {
|
|
return Integer.compare(System.identityHashCode(p1), System.identityHashCode(p2));
|
|
});
|
|
|
|
- protected final TreeSet<PlayerLoaderData> chunkSendWaitQueue = new TreeSet<>((final PlayerLoaderData p1, final PlayerLoaderData p2) -> {
|
|
+ protected final NavigableSet<PlayerLoaderData> chunkSendWaitQueue = new ConcurrentSkipListSet<>((final PlayerLoaderData p1, final PlayerLoaderData p2) -> {
|
|
if (p1 == p2) {
|
|
return 0;
|
|
}
|
|
@@ -308,8 +307,8 @@ public final class PlayerChunkLoader {
|
|
});
|
|
}
|
|
|
|
- protected final LongOpenHashSet isTargetedForPlayerLoad = new LongOpenHashSet();
|
|
- protected final LongOpenHashSet chunkTicketTracker = new LongOpenHashSet();
|
|
+ protected final LongSet isTargetedForPlayerLoad = new ConcurrentLongLinkedOpenHashSet();
|
|
+ protected final LongSet chunkTicketTracker = new ConcurrentLongLinkedOpenHashSet();
|
|
|
|
public boolean isChunkNearPlayers(final int chunkX, final int chunkZ) {
|
|
final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInSendRange = this.broadcastMap.getObjectsInRange(chunkX, chunkZ);
|
|
@@ -523,17 +522,16 @@ public final class PlayerChunkLoader {
|
|
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()) {
|
|
@@ -542,10 +540,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;
|
|
@@ -554,19 +551,12 @@ public final class PlayerChunkLoader {
|
|
if (!concurrentChunkSends.compareAndSet(currSends, currSends + 1)) {
|
|
continue;
|
|
}
|
|
-
|
|
// send chunk
|
|
-
|
|
- final 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;
|
|
}
|
|
|
|
@@ -581,17 +571,18 @@ public final class PlayerChunkLoader {
|
|
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);
|
|
}
|
|
}
|
|
|
|
@@ -618,16 +609,12 @@ public final class PlayerChunkLoader {
|
|
final int maxLoads = this.getMaxChunkLoads();
|
|
final long time = System.nanoTime();
|
|
boolean updatedCounters = false;
|
|
- for (;;) {
|
|
- final 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;
|
|
}
|
|
|
|
@@ -786,11 +773,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 = new ConcurrentLongLinkedOpenHashSet();
|
|
+ protected final LongSet chunksToBeSent = new ConcurrentLongLinkedOpenHashSet();
|
|
|
|
- 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;
|
|
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..0aa279028181726f2ec211915688d4434a7178d6 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,72 +234,59 @@ 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());
|
|
- 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 recursively update entity chunk status for entity " + entity);
|
|
return;
|
|
}
|
|
|
|
+ final Boolean ticketBlockBefore = this.world.chunkTaskScheduler.chunkHolderManager.blockTicketUpdates();
|
|
try {
|
|
- final Boolean ticketBlockBefore = this.world.chunkTaskScheduler.chunkHolderManager.blockTicketUpdates();
|
|
+ entity.updatingSectionStatus = true;
|
|
try {
|
|
- entity.updatingSectionStatus = true;
|
|
- try {
|
|
- if (created) {
|
|
- EntityLookup.this.worldCallback.onCreated(entity);
|
|
- }
|
|
+ if (created) {
|
|
+ EntityLookup.this.worldCallback.onCreated(entity);
|
|
+ }
|
|
|
|
- if (oldVisibility == newVisibility) {
|
|
- if (moved && newVisibility.isAccessible()) {
|
|
- EntityLookup.this.worldCallback.onSectionChange(entity);
|
|
- }
|
|
- return;
|
|
+ if (oldVisibility == newVisibility) {
|
|
+ if (moved && newVisibility.isAccessible()) {
|
|
+ EntityLookup.this.worldCallback.onSectionChange(entity);
|
|
}
|
|
+ return;
|
|
+ }
|
|
|
|
- if (newVisibility.ordinal() > oldVisibility.ordinal()) {
|
|
- // status upgrade
|
|
- if (!oldVisibility.isAccessible() && newVisibility.isAccessible()) {
|
|
- this.accessibleEntities.add(entity);
|
|
- EntityLookup.this.worldCallback.onTrackingStart(entity);
|
|
- }
|
|
-
|
|
- if (!oldVisibility.isTicking() && newVisibility.isTicking()) {
|
|
- EntityLookup.this.worldCallback.onTickingStart(entity);
|
|
- }
|
|
- } else {
|
|
- // status downgrade
|
|
- if (oldVisibility.isTicking() && !newVisibility.isTicking()) {
|
|
- EntityLookup.this.worldCallback.onTickingEnd(entity);
|
|
- }
|
|
-
|
|
- if (oldVisibility.isAccessible() && !newVisibility.isAccessible()) {
|
|
- this.accessibleEntities.remove(entity);
|
|
- EntityLookup.this.worldCallback.onTrackingEnd(entity);
|
|
- }
|
|
+ if (newVisibility.ordinal() > oldVisibility.ordinal()) {
|
|
+ // status upgrade
|
|
+ if (!oldVisibility.isAccessible() && newVisibility.isAccessible()) {
|
|
+ this.accessibleEntities.add(entity);
|
|
+ EntityLookup.this.worldCallback.onTrackingStart(entity);
|
|
}
|
|
|
|
- if (moved && newVisibility.isAccessible()) {
|
|
- EntityLookup.this.worldCallback.onSectionChange(entity);
|
|
+ if (!oldVisibility.isTicking() && newVisibility.isTicking()) {
|
|
+ EntityLookup.this.worldCallback.onTickingStart(entity);
|
|
+ }
|
|
+ } else {
|
|
+ // status downgrade
|
|
+ if (oldVisibility.isTicking() && !newVisibility.isTicking()) {
|
|
+ EntityLookup.this.worldCallback.onTickingEnd(entity);
|
|
}
|
|
|
|
- if (destroyed) {
|
|
- EntityLookup.this.worldCallback.onDestroyed(entity);
|
|
+ if (oldVisibility.isAccessible() && !newVisibility.isAccessible()) {
|
|
+ this.accessibleEntities.remove(entity);
|
|
+ EntityLookup.this.worldCallback.onTrackingEnd(entity);
|
|
}
|
|
- } finally {
|
|
- entity.updatingSectionStatus = false;
|
|
+ }
|
|
+
|
|
+ if (moved && newVisibility.isAccessible()) {
|
|
+ EntityLookup.this.worldCallback.onSectionChange(entity);
|
|
+ }
|
|
+
|
|
+ if (destroyed) {
|
|
+ EntityLookup.this.worldCallback.onDestroyed(entity);
|
|
}
|
|
} finally {
|
|
- this.world.chunkTaskScheduler.chunkHolderManager.unblockTicketUpdates(ticketBlockBefore);
|
|
+ entity.updatingSectionStatus = false;
|
|
}
|
|
} finally {
|
|
- if (slices != null) {
|
|
- slices.stopPreventingStatusUpdates(false);
|
|
- }
|
|
+ this.world.chunkTaskScheduler.chunkHolderManager.unblockTicketUpdates(ticketBlockBefore);
|
|
}
|
|
}
|
|
|
|
@@ -305,20 +295,20 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
|
|
}
|
|
|
|
public void addLegacyChunkEntities(final List<Entity> entities) {
|
|
- for (int i = 0, len = entities.size(); i < len; ++i) {
|
|
- this.addEntity(entities.get(i), true);
|
|
+ for (Entity entity : entities) {
|
|
+ this.addEntity(entity, true);
|
|
}
|
|
}
|
|
|
|
public void addEntityChunkEntities(final List<Entity> entities) {
|
|
- for (int i = 0, len = entities.size(); i < len; ++i) {
|
|
- this.addEntity(entities.get(i), true);
|
|
+ for (Entity entity : entities) {
|
|
+ this.addEntity(entity, true);
|
|
}
|
|
}
|
|
|
|
public void addWorldGenChunkEntities(final List<Entity> entities) {
|
|
- for (int i = 0, len = entities.size(); i < len; ++i) {
|
|
- this.addEntity(entities.get(i), false);
|
|
+ for (Entity entity : entities) {
|
|
+ this.addEntity(entity, false);
|
|
}
|
|
}
|
|
|
|
@@ -346,11 +336,6 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
|
|
return false;
|
|
}
|
|
|
|
- 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());
|
|
- return false;
|
|
- }
|
|
-
|
|
if (fromDisk) {
|
|
ChunkSystem.onEntityPreAdd(this.world, entity);
|
|
if (entity.isRemoved()) {
|
|
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/io/papermc/paper/util/TickThread.java b/src/main/java/io/papermc/paper/util/TickThread.java
|
|
index fc57850b80303fcade89ca95794f63910404a407..da6c6b6691c9645722e5fc6a1319e9c07c130d3d 100644
|
|
--- a/src/main/java/io/papermc/paper/util/TickThread.java
|
|
+++ b/src/main/java/io/papermc/paper/util/TickThread.java
|
|
@@ -1,9 +1,12 @@
|
|
package io.papermc.paper.util;
|
|
|
|
+import co.m2ek4u.hearse.ForkJoinTickThread;
|
|
import net.minecraft.server.MinecraftServer;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.world.entity.Entity;
|
|
import org.bukkit.Bukkit;
|
|
+
|
|
+import java.util.concurrent.ForkJoinWorkerThread;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
public class TickThread extends Thread {
|
|
@@ -74,14 +77,14 @@ public class TickThread extends Thread {
|
|
}
|
|
|
|
public static boolean isTickThread() {
|
|
- return Thread.currentThread() instanceof TickThread;
|
|
+ return Thread.currentThread() instanceof TickThread || ForkJoinTickThread.isAnotherForKJoinTickThread();
|
|
}
|
|
|
|
public static boolean isTickThreadFor(final ServerLevel world, final int chunkX, final int chunkZ) {
|
|
- return Thread.currentThread() instanceof TickThread;
|
|
+ return Thread.currentThread() instanceof TickThread || ForkJoinTickThread.isAnotherForKJoinTickThread();
|
|
}
|
|
|
|
public static boolean isTickThreadFor(final Entity entity) {
|
|
- return Thread.currentThread() instanceof TickThread;
|
|
+ return Thread.currentThread() instanceof TickThread || ForkJoinTickThread.isAnotherForKJoinTickThread();
|
|
}
|
|
}
|
|
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..09cd3f34eb95ef46df0bd1a81924a9f709bc1adc 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;
|
|
}
|
|
@@ -140,9 +141,7 @@ 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;
|
|
}
|
|
@@ -157,7 +156,7 @@ public final class ChunkEntitySlices {
|
|
// Paper end - optimise CraftChunk#getEntities
|
|
|
|
public boolean isEmpty() {
|
|
- return this.entities.size() == 0;
|
|
+ return this.entities.isEmpty();
|
|
}
|
|
|
|
public void mergeInto(final ChunkEntitySlices slices) {
|
|
@@ -168,17 +167,6 @@ public final class ChunkEntitySlices {
|
|
}
|
|
}
|
|
|
|
- private boolean preventStatusUpdates;
|
|
- public boolean startPreventingStatusUpdates() {
|
|
- final boolean ret = this.preventStatusUpdates;
|
|
- this.preventStatusUpdates = true;
|
|
- return ret;
|
|
- }
|
|
-
|
|
- public void stopPreventingStatusUpdates(final boolean prev) {
|
|
- this.preventStatusUpdates = prev;
|
|
- }
|
|
-
|
|
public void updateStatus(final ChunkHolder.FullChunkStatus status, final EntityLookup lookup) {
|
|
this.status = status;
|
|
|
|
@@ -209,7 +197,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 +222,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 +300,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 +316,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 +326,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 +338,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 +355,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;
|
|
}
|
|
}
|
|
@@ -377,7 +365,7 @@ public final class ChunkEntitySlices {
|
|
protected final ChunkEntitySlices manager;
|
|
protected final long[] nonEmptyBitset;
|
|
protected final BasicEntityList<Entity>[] entitiesBySection;
|
|
- protected int count;
|
|
+ protected volatile int count;
|
|
|
|
public EntityCollectionBySection(final ChunkEntitySlices manager) {
|
|
this.manager = manager;
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/ConcurrentArrayDeque.java b/src/main/java/net/himeki/mcmtfabric/parallelised/ConcurrentArrayDeque.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..3c29129dc02ddcfaad026d1f81e5da879a0d64cb
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/ConcurrentArrayDeque.java
|
|
@@ -0,0 +1,4 @@
|
|
+package net.himeki.mcmtfabric.parallelised;
|
|
+
|
|
+public class ConcurrentArrayDeque {
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/ConcurrentCollections.java b/src/main/java/net/himeki/mcmtfabric/parallelised/ConcurrentCollections.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..67dd5fe624fe4428d8907000cb23a33485fd6bd9
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/ConcurrentCollections.java
|
|
@@ -0,0 +1,41 @@
|
|
+package net.himeki.mcmtfabric.parallelised;
|
|
+
|
|
+import org.apache.logging.log4j.LogManager;
|
|
+import org.apache.logging.log4j.Logger;
|
|
+
|
|
+import java.util.*;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+import java.util.concurrent.ConcurrentLinkedDeque;
|
|
+import java.util.concurrent.CopyOnWriteArrayList;
|
|
+import java.util.stream.Collector;
|
|
+import java.util.stream.Collectors;
|
|
+
|
|
+public class ConcurrentCollections {
|
|
+
|
|
+ private static final Logger LOGGER = LogManager.getLogger();
|
|
+
|
|
+ public static <T> Set<T> newHashSet() {
|
|
+ //LOGGER.info("Concurrent hash set created");
|
|
+ return Collections.newSetFromMap(new ConcurrentHashMap<T, Boolean>());
|
|
+ }
|
|
+
|
|
+ public static <T, U> Map<T, U> newHashMap() {
|
|
+ //LOGGER.info("Concurrent hash map created");
|
|
+ return new ConcurrentHashMap<T, U>();
|
|
+ }
|
|
+
|
|
+ public static <T> List<T> newLinkedList() {
|
|
+ LOGGER.info("Concurrent \"linked\" list created");
|
|
+ return new CopyOnWriteArrayList<T>();
|
|
+ }
|
|
+
|
|
+ public static <T> Collector<T, ?, List<T>> toList() {
|
|
+ return Collectors.toCollection(CopyOnWriteArrayList::new);
|
|
+ }
|
|
+
|
|
+ public static <T> Queue<T> newArrayDeque() {
|
|
+ LOGGER.info("Concurrent \"array\" deque created");
|
|
+ return new ConcurrentLinkedDeque<T>();
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/ConcurrentDoublyLinkedList.java b/src/main/java/net/himeki/mcmtfabric/parallelised/ConcurrentDoublyLinkedList.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..22b9d217dc06caaf8fbec21f0e31aa1cd13144ee
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/ConcurrentDoublyLinkedList.java
|
|
@@ -0,0 +1,945 @@
|
|
+package net.himeki.mcmtfabric.parallelised;
|
|
+
|
|
+/*
|
|
+ * From: http://www.java2s.com/Code/Java/Collections-Data-Structure/ConcurrentDoublyLinkedList.htm
|
|
+ *
|
|
+ * Written by Doug Lea with assistance from members of JCP JSR-166
|
|
+ * Expert Group and released to the public domain, as explained at
|
|
+ * http://creativecommons.org/licenses/publicdomain
|
|
+ *
|
|
+ * Modified to actually implement List<E>
|
|
+ */
|
|
+
|
|
+import java.util.AbstractCollection;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Collection;
|
|
+import java.util.ConcurrentModificationException;
|
|
+import java.util.Deque;
|
|
+import java.util.Iterator;
|
|
+import java.util.List;
|
|
+import java.util.ListIterator;
|
|
+import java.util.NoSuchElementException;
|
|
+import java.util.concurrent.atomic.AtomicReference;
|
|
+
|
|
+import org.apache.commons.lang3.NotImplementedException;
|
|
+
|
|
+/**
|
|
+ * A concurrent linked-list implementation of a {@link Deque} (double-ended
|
|
+ * queue). Concurrent insertion, removal, and access operations execute safely
|
|
+ * across multiple threads. Iterators are <i>weakly consistent</i>, returning
|
|
+ * elements reflecting the state of the deque at some point at or since the
|
|
+ * creation of the iterator. They do <em>not</em> throw
|
|
+ * {@link ConcurrentModificationException}, and may proceed concurrently with
|
|
+ * other operations.
|
|
+ *
|
|
+ * <p>
|
|
+ * This class and its iterators implement all of the <em>optional</em> methods
|
|
+ * of the {@link Collection} and {@link Iterator} interfaces. Like most other
|
|
+ * concurrent collection implementations, this class does not permit the use of
|
|
+ * <tt>null</tt> elements. because some null arguments and return values cannot
|
|
+ * be reliably distinguished from the absence of elements. Arbitrarily, the
|
|
+ * {@link Collection#remove} method is mapped to <tt>removeFirstOccurrence</tt>,
|
|
+ * and {@link Collection#add} is mapped to <tt>addLast</tt>.
|
|
+ *
|
|
+ * <p>
|
|
+ * Beware that, unlike in most collections, the <tt>size</tt> method is
|
|
+ * <em>NOT</em> a constant-time operation. Because of the asynchronous nature of
|
|
+ * these deques, determining the current number of elements requires a traversal
|
|
+ * of the elements.
|
|
+ *
|
|
+ * <p>
|
|
+ * This class is <tt>Serializable</tt>, but relies on default serialization
|
|
+ * mechanisms. Usually, it is a better idea for any serializable class using a
|
|
+ * <tt>ConcurrentLinkedDeque</tt> to instead serialize a snapshot of the
|
|
+ * elements obtained by method <tt>toArray</tt>.
|
|
+ *
|
|
+ * @author Doug Lea
|
|
+ * @param <E> the type of elements held in this collection
|
|
+ */
|
|
+
|
|
+public class ConcurrentDoublyLinkedList<E> extends AbstractCollection<E> implements List<E>, java.io.Serializable {
|
|
+
|
|
+ /*
|
|
+ * This is an adaptation of an algorithm described in Paul Martin's "A Practical
|
|
+ * Lock-Free Doubly-Linked List". Sun Labs Tech report. The basic idea is to
|
|
+ * primarily rely on next-pointers to ensure consistency. Prev-pointers are in
|
|
+ * part optimistic, reconstructed using forward pointers as needed. The main
|
|
+ * forward list uses a variant of HM-list algorithm similar to the one used in
|
|
+ * ConcurrentSkipListMap class, but a little simpler. It is also basically
|
|
+ * similar to the approach in Edya Ladan-Mozes and Nir Shavit "An Optimistic
|
|
+ * Approach to Lock-Free FIFO Queues" in DISC04.
|
|
+ *
|
|
+ * Quoting a summary in Paul Martin's tech report:
|
|
+ *
|
|
+ * All cleanups work to maintain these invariants: (1) forward pointers are the
|
|
+ * ground truth. (2) forward pointers to dead nodes can be improved by swinging
|
|
+ * them further forward around the dead node. (2.1) forward pointers are still
|
|
+ * correct when pointing to dead nodes, and forward pointers from dead nodes are
|
|
+ * left as they were when the node was deleted. (2.2) multiple dead nodes may
|
|
+ * point forward to the same node. (3) backward pointers were correct when they
|
|
+ * were installed (3.1) backward pointers are correct when pointing to any node
|
|
+ * which points forward to them, but since more than one forward pointer may
|
|
+ * point to them, the live one is best. (4) backward pointers that are out of
|
|
+ * date due to deletion point to a deleted node, and need to point further back
|
|
+ * until they point to the live node that points to their source. (5) backward
|
|
+ * pointers that are out of date due to insertion point too far backwards, so
|
|
+ * shortening their scope (by searching forward) fixes them. (6) backward
|
|
+ * pointers from a dead node cannot be "improved" since there may be no live
|
|
+ * node pointing forward to their origin. (However, it does no harm to try to
|
|
+ * improve them while racing with a deletion.)
|
|
+ *
|
|
+ *
|
|
+ * Notation guide for local variables n, b, f : a node, its predecessor, and
|
|
+ * successor s : some other successor
|
|
+ */
|
|
+
|
|
+ // Minor convenience utilities
|
|
+
|
|
+ /**
|
|
+ * Returns true if given reference is non-null and isn't a header, trailer, or
|
|
+ * marker.
|
|
+ *
|
|
+ * @param n (possibly null) node
|
|
+ * @return true if n exists as a user node
|
|
+ */
|
|
+ private static boolean usable(Node<?> n) {
|
|
+ return n != null && !n.isSpecial();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Throws NullPointerException if argument is null
|
|
+ *
|
|
+ * @param v the element
|
|
+ */
|
|
+ private static void checkNullArg(Object v) {
|
|
+ if (v == null)
|
|
+ throw new NullPointerException();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns element unless it is null, in which case throws
|
|
+ * NoSuchElementException.
|
|
+ *
|
|
+ * @param v the element
|
|
+ * @return the element
|
|
+ */
|
|
+ private E screenNullResult(E v) {
|
|
+ if (v == null)
|
|
+ throw new NoSuchElementException();
|
|
+ return v;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates an array list and fills it with elements of this list. Used by
|
|
+ * toArray.
|
|
+ *
|
|
+ * @return the arrayList
|
|
+ */
|
|
+ private ArrayList<E> toArrayList() {
|
|
+ ArrayList<E> c = new ArrayList<E>();
|
|
+ for (Node<E> n = header.forward(); n != null; n = n.forward())
|
|
+ c.add(n.element);
|
|
+ return c;
|
|
+ }
|
|
+
|
|
+ // Fields and constructors
|
|
+
|
|
+ private static final long serialVersionUID = 876323262645176354L;
|
|
+
|
|
+ /**
|
|
+ * List header. First usable node is at header.forward().
|
|
+ */
|
|
+ private final Node<E> header;
|
|
+
|
|
+ /**
|
|
+ * List trailer. Last usable node is at trailer.back().
|
|
+ */
|
|
+ private final Node<E> trailer;
|
|
+
|
|
+ /**
|
|
+ * Constructs an empty deque.
|
|
+ */
|
|
+ public ConcurrentDoublyLinkedList() {
|
|
+ Node<E> h = new Node<E>(null, null, null);
|
|
+ Node<E> t = new Node<E>(null, null, h);
|
|
+ h.setNext(t);
|
|
+ header = h;
|
|
+ trailer = t;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Constructs a deque containing the elements of the specified collection, in
|
|
+ * the order they are returned by the collection's iterator.
|
|
+ *
|
|
+ * @param c the collection whose elements are to be placed into this deque.
|
|
+ * @throws NullPointerException if <tt>c</tt> or any element within it is
|
|
+ * <tt>null</tt>
|
|
+ */
|
|
+ public ConcurrentDoublyLinkedList(Collection<? extends E> c) {
|
|
+ this();
|
|
+ addAll(c);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Prepends the given element at the beginning of this deque.
|
|
+ *
|
|
+ * @param o the element to be inserted at the beginning of this deque.
|
|
+ * @throws NullPointerException if the specified element is <tt>null</tt>
|
|
+ */
|
|
+ public void addFirst(E o) {
|
|
+ checkNullArg(o);
|
|
+ while (header.append(o) == null)
|
|
+ ;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Appends the given element to the end of this deque. This is identical in
|
|
+ * function to the <tt>add</tt> method.
|
|
+ *
|
|
+ * @param o the element to be inserted at the end of this deque.
|
|
+ * @throws NullPointerException if the specified element is <tt>null</tt>
|
|
+ */
|
|
+ public void addLast(E o) {
|
|
+ checkNullArg(o);
|
|
+ while (trailer.prepend(o) == null)
|
|
+ ;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Prepends the given element at the beginning of this deque.
|
|
+ *
|
|
+ * @param o the element to be inserted at the beginning of this deque.
|
|
+ * @return <tt>true</tt> always
|
|
+ * @throws NullPointerException if the specified element is <tt>null</tt>
|
|
+ */
|
|
+ public boolean offerFirst(E o) {
|
|
+ addFirst(o);
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Appends the given element to the end of this deque. (Identical in function to
|
|
+ * the <tt>add</tt> method; included only for consistency.)
|
|
+ *
|
|
+ * @param o the element to be inserted at the end of this deque.
|
|
+ * @return <tt>true</tt> always
|
|
+ * @throws NullPointerException if the specified element is <tt>null</tt>
|
|
+ */
|
|
+ public boolean offerLast(E o) {
|
|
+ addLast(o);
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Retrieves, but does not remove, the first element of this deque, or returns
|
|
+ * null if this deque is empty.
|
|
+ *
|
|
+ * @return the first element of this queue, or <tt>null</tt> if empty.
|
|
+ */
|
|
+ public E peekFirst() {
|
|
+ Node<E> n = header.successor();
|
|
+ return (n == null) ? null : n.element;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Retrieves, but does not remove, the last element of this deque, or returns
|
|
+ * null if this deque is empty.
|
|
+ *
|
|
+ * @return the last element of this deque, or <tt>null</tt> if empty.
|
|
+ */
|
|
+ public E peekLast() {
|
|
+ Node<E> n = trailer.predecessor();
|
|
+ return (n == null) ? null : n.element;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns the first element in this deque.
|
|
+ *
|
|
+ * @return the first element in this deque.
|
|
+ * @throws NoSuchElementException if this deque is empty.
|
|
+ */
|
|
+ public E getFirst() {
|
|
+ return screenNullResult(peekFirst());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns the last element in this deque.
|
|
+ *
|
|
+ * @return the last element in this deque.
|
|
+ * @throws NoSuchElementException if this deque is empty.
|
|
+ */
|
|
+ public E getLast() {
|
|
+ return screenNullResult(peekLast());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Retrieves and removes the first element of this deque, or returns null if
|
|
+ * this deque is empty.
|
|
+ *
|
|
+ * @return the first element of this deque, or <tt>null</tt> if empty.
|
|
+ */
|
|
+ public E pollFirst() {
|
|
+ for (;;) {
|
|
+ Node<E> n = header.successor();
|
|
+ if (!usable(n))
|
|
+ return null;
|
|
+ if (n.delete())
|
|
+ return n.element;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Retrieves and removes the last element of this deque, or returns null if this
|
|
+ * deque is empty.
|
|
+ *
|
|
+ * @return the last element of this deque, or <tt>null</tt> if empty.
|
|
+ */
|
|
+ public E pollLast() {
|
|
+ for (;;) {
|
|
+ Node<E> n = trailer.predecessor();
|
|
+ if (!usable(n))
|
|
+ return null;
|
|
+ if (n.delete())
|
|
+ return n.element;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Removes and returns the first element from this deque.
|
|
+ *
|
|
+ * @return the first element from this deque.
|
|
+ * @throws NoSuchElementException if this deque is empty.
|
|
+ */
|
|
+ public E removeFirst() {
|
|
+ return screenNullResult(pollFirst());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Removes and returns the last element from this deque.
|
|
+ *
|
|
+ * @return the last element from this deque.
|
|
+ * @throws NoSuchElementException if this deque is empty.
|
|
+ */
|
|
+ public E removeLast() {
|
|
+ return screenNullResult(pollLast());
|
|
+ }
|
|
+
|
|
+ // *** Queue and stack methods ***
|
|
+ public boolean offer(E e) {
|
|
+ return offerLast(e);
|
|
+ }
|
|
+
|
|
+ public boolean add(E e) {
|
|
+ return offerLast(e);
|
|
+ }
|
|
+
|
|
+ public E poll() {
|
|
+ return pollFirst();
|
|
+ }
|
|
+
|
|
+ public E remove() {
|
|
+ return removeFirst();
|
|
+ }
|
|
+
|
|
+ public E peek() {
|
|
+ return peekFirst();
|
|
+ }
|
|
+
|
|
+ public E element() {
|
|
+ return getFirst();
|
|
+ }
|
|
+
|
|
+ public void push(E e) {
|
|
+ addFirst(e);
|
|
+ }
|
|
+
|
|
+ public E pop() {
|
|
+ return removeFirst();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Removes the first element <tt>e</tt> such that <tt>o.equals(e)</tt>, if such
|
|
+ * an element exists in this deque. If the deque does not contain the element,
|
|
+ * it is unchanged.
|
|
+ *
|
|
+ * @param o element to be removed from this deque, if present.
|
|
+ * @return <tt>true</tt> if the deque contained the specified element.
|
|
+ * @throws NullPointerException if the specified element is <tt>null</tt>
|
|
+ */
|
|
+ public boolean removeFirstOccurrence(Object o) {
|
|
+ checkNullArg(o);
|
|
+ for (;;) {
|
|
+ Node<E> n = header.forward();
|
|
+ for (;;) {
|
|
+ if (n == null)
|
|
+ return false;
|
|
+ if (o.equals(n.element)) {
|
|
+ if (n.delete())
|
|
+ return true;
|
|
+ else
|
|
+ break; // restart if interference
|
|
+ }
|
|
+ n = n.forward();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Removes the last element <tt>e</tt> such that <tt>o.equals(e)</tt>, if such
|
|
+ * an element exists in this deque. If the deque does not contain the element,
|
|
+ * it is unchanged.
|
|
+ *
|
|
+ * @param o element to be removed from this deque, if present.
|
|
+ * @return <tt>true</tt> if the deque contained the specified element.
|
|
+ * @throws NullPointerException if the specified element is <tt>null</tt>
|
|
+ */
|
|
+ public boolean removeLastOccurrence(Object o) {
|
|
+ checkNullArg(o);
|
|
+ for (;;) {
|
|
+ Node<E> s = trailer;
|
|
+ for (;;) {
|
|
+ Node<E> n = s.back();
|
|
+ if (s.isDeleted() || (n != null && n.successor() != s))
|
|
+ break; // restart if pred link is suspect.
|
|
+ if (n == null)
|
|
+ return false;
|
|
+ if (o.equals(n.element)) {
|
|
+ if (n.delete())
|
|
+ return true;
|
|
+ else
|
|
+ break; // restart if interference
|
|
+ }
|
|
+ s = n;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns <tt>true</tt> if this deque contains at least one element <tt>e</tt>
|
|
+ * such that <tt>o.equals(e)</tt>.
|
|
+ *
|
|
+ * @param o element whose presence in this deque is to be tested.
|
|
+ * @return <tt>true</tt> if this deque contains the specified element.
|
|
+ */
|
|
+ public boolean contains(Object o) {
|
|
+ if (o == null)
|
|
+ return false;
|
|
+ for (Node<E> n = header.forward(); n != null; n = n.forward())
|
|
+ if (o.equals(n.element))
|
|
+ return true;
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns <tt>true</tt> if this collection contains no elements.
|
|
+ * <p>
|
|
+ *
|
|
+ * @return <tt>true</tt> if this collection contains no elements.
|
|
+ */
|
|
+ public boolean isEmpty() {
|
|
+ return !usable(header.successor());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns the number of elements in this deque. If this deque contains more
|
|
+ * than <tt>Integer.MAX_VALUE</tt> elements, it returns
|
|
+ * <tt>Integer.MAX_VALUE</tt>.
|
|
+ *
|
|
+ * <p>
|
|
+ * Beware that, unlike in most collections, this method is <em>NOT</em> a
|
|
+ * constant-time operation. Because of the asynchronous nature of these deques,
|
|
+ * determining the current number of elements requires traversing them all to
|
|
+ * count them. Additionally, it is possible for the size to change during
|
|
+ * execution of this method, in which case the returned result will be
|
|
+ * inaccurate. Thus, this method is typically not very useful in concurrent
|
|
+ * applications.
|
|
+ *
|
|
+ * @return the number of elements in this deque.
|
|
+ */
|
|
+ public int size() {
|
|
+ long count = 0;
|
|
+ for (Node<E> n = header.forward(); n != null; n = n.forward())
|
|
+ ++count;
|
|
+ return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Removes the first element <tt>e</tt> such that <tt>o.equals(e)</tt>, if such
|
|
+ * an element exists in this deque. If the deque does not contain the element,
|
|
+ * it is unchanged.
|
|
+ *
|
|
+ * @param o element to be removed from this deque, if present.
|
|
+ * @return <tt>true</tt> if the deque contained the specified element.
|
|
+ * @throws NullPointerException if the specified element is <tt>null</tt>
|
|
+ */
|
|
+ public boolean remove(Object o) {
|
|
+ return removeFirstOccurrence(o);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Appends all of the elements in the specified collection to the end of this
|
|
+ * deque, in the order that they are returned by the specified collection's
|
|
+ * iterator. The behavior of this operation is undefined if the specified
|
|
+ * collection is modified while the operation is in progress. (This implies that
|
|
+ * the behavior of this call is undefined if the specified Collection is this
|
|
+ * deque, and this deque is nonempty.)
|
|
+ *
|
|
+ * @param c the elements to be inserted into this deque.
|
|
+ * @return <tt>true</tt> if this deque changed as a result of the call.
|
|
+ * @throws NullPointerException if <tt>c</tt> or any element within it is
|
|
+ * <tt>null</tt>
|
|
+ */
|
|
+ public boolean addAll(Collection<? extends E> c) {
|
|
+ Iterator<? extends E> it = c.iterator();
|
|
+ if (!it.hasNext())
|
|
+ return false;
|
|
+ do {
|
|
+ addLast(it.next());
|
|
+ } while (it.hasNext());
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Removes all of the elements from this deque.
|
|
+ */
|
|
+ public void clear() {
|
|
+ while (pollFirst() != null)
|
|
+ ;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns an array containing all of the elements in this deque in the correct
|
|
+ * order.
|
|
+ *
|
|
+ * @return an array containing all of the elements in this deque in the correct
|
|
+ * order.
|
|
+ */
|
|
+ public Object[] toArray() {
|
|
+ return toArrayList().toArray();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns an array containing all of the elements in this deque in the correct
|
|
+ * order; the runtime type of the returned array is that of the specified array.
|
|
+ * If the deque fits in the specified array, it is returned therein. Otherwise,
|
|
+ * a new array is allocated with the runtime type of the specified array and the
|
|
+ * size of this deque.
|
|
+ * <p>
|
|
+ *
|
|
+ * If the deque fits in the specified array with room to spare (i.e., the array
|
|
+ * has more elements than the deque), the element in the array immediately
|
|
+ * following the end of the collection is set to null. This is useful in
|
|
+ * determining the length of the deque <i>only</i> if the caller knows that the
|
|
+ * deque does not contain any null elements.
|
|
+ *
|
|
+ * @param a the array into which the elements of the deque are to be stored, if
|
|
+ * it is big enough; otherwise, a new array of the same runtime type is
|
|
+ * allocated for this purpose.
|
|
+ * @return an array containing the elements of the deque.
|
|
+ * @throws ArrayStoreException if the runtime type of a is not a supertype of
|
|
+ * the runtime type of every element in this deque.
|
|
+ * @throws NullPointerException if the specified array is null.
|
|
+ */
|
|
+ public <T> T[] toArray(T[] a) {
|
|
+ return toArrayList().toArray(a);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns a weakly consistent iterator over the elements in this deque, in
|
|
+ * first-to-last order. The <tt>next</tt> method returns elements reflecting the
|
|
+ * state of the deque at some point at or since the creation of the iterator.
|
|
+ * The method does <em>not</em> throw {@link ConcurrentModificationException},
|
|
+ * and may proceed concurrently with other operations.
|
|
+ *
|
|
+ * @return an iterator over the elements in this deque
|
|
+ */
|
|
+ public Iterator<E> iterator() {
|
|
+ return new CLDIterator();
|
|
+ }
|
|
+
|
|
+ final class CLDIterator implements Iterator<E> {
|
|
+ Node<E> last;
|
|
+
|
|
+ Node<E> next = header.forward();
|
|
+
|
|
+ public boolean hasNext() {
|
|
+ return next != null;
|
|
+ }
|
|
+
|
|
+ public E next() {
|
|
+ Node<E> l = last = next;
|
|
+ if (l == null)
|
|
+ throw new NoSuchElementException();
|
|
+ next = next.forward();
|
|
+ return l.element;
|
|
+ }
|
|
+
|
|
+ public void remove() {
|
|
+ Node<E> l = last;
|
|
+ if (l == null)
|
|
+ throw new IllegalStateException();
|
|
+ while (!l.delete() && !l.isDeleted())
|
|
+ ;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(int index, Collection<? extends E> c) {
|
|
+ throw new NotImplementedException("TODO");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public E get(int index) {
|
|
+ Node<E> current = header.successor();
|
|
+ if (current == null) {
|
|
+ throw new IndexOutOfBoundsException();
|
|
+ }
|
|
+ for (; index > 0; index --) {
|
|
+ current = current.successor();
|
|
+ if (current == null) {
|
|
+ throw new IndexOutOfBoundsException();
|
|
+ }
|
|
+ }
|
|
+ return current.element;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public E set(int index, E element) {
|
|
+ throw new NotImplementedException("INVALID");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void add(int index, E element) {
|
|
+ throw new NotImplementedException("INVALID");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public E remove(int index) {
|
|
+ throw new NotImplementedException("INVALID");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int indexOf(Object o) {
|
|
+ throw new NotImplementedException("INVALID");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int lastIndexOf(Object o) {
|
|
+ throw new NotImplementedException("INVALID");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ListIterator<E> listIterator() {
|
|
+ throw new NotImplementedException("INVALID");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ListIterator<E> listIterator(int index) {
|
|
+ throw new NotImplementedException("INVALID");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<E> subList(int fromIndex, int toIndex) {
|
|
+ throw new NotImplementedException("INVALID");
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Linked Nodes. As a minor efficiency hack, this class opportunistically
|
|
+ * inherits from AtomicReference, with the atomic ref used as the "next" link.
|
|
+ *
|
|
+ * Nodes are in doubly-linked lists. There are three kinds of special nodes,
|
|
+ * distinguished by: * The list header has a null prev link * The list trailer
|
|
+ * has a null next link * A deletion marker has a prev link pointing to itself.
|
|
+ * All three kinds of special nodes have null element fields.
|
|
+ *
|
|
+ * Regular nodes have non-null element, next, and prev fields. To avoid visible
|
|
+ * inconsistencies when deletions overlap element replacement, replacements are
|
|
+ * done by replacing the node, not just setting the element.
|
|
+ *
|
|
+ * Nodes can be traversed by read-only ConcurrentLinkedDeque class operations
|
|
+ * just by following raw next pointers, so long as they ignore any special nodes
|
|
+ * seen along the way. (This is automated in method forward.) However, traversal
|
|
+ * using prev pointers is not guaranteed to see all live nodes since a prev
|
|
+ * pointer of a deleted node can become unrecoverably stale.
|
|
+ */
|
|
+
|
|
+class Node<E> extends AtomicReference<Node<E>> {
|
|
+
|
|
+ private static final long serialVersionUID = 6640557564507962862L;
|
|
+
|
|
+ private volatile Node<E> prev;
|
|
+
|
|
+ final E element;
|
|
+
|
|
+ /** Creates a node with given contents */
|
|
+ Node(E element, Node<E> next, Node<E> prev) {
|
|
+ super(next);
|
|
+ this.prev = prev;
|
|
+ this.element = element;
|
|
+ }
|
|
+
|
|
+ /** Creates a marker node with given successor */
|
|
+ Node(Node<E> next) {
|
|
+ super(next);
|
|
+ this.prev = this;
|
|
+ this.element = null;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets next link (which is actually the value held as atomic reference).
|
|
+ */
|
|
+ private Node<E> getNext() {
|
|
+ return get();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Sets next link
|
|
+ *
|
|
+ * @param n the next node
|
|
+ */
|
|
+ void setNext(Node<E> n) {
|
|
+ set(n);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * compareAndSet next link
|
|
+ */
|
|
+ private boolean casNext(Node<E> cmp, Node<E> val) {
|
|
+ return compareAndSet(cmp, val);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Gets prev link
|
|
+ */
|
|
+ private Node<E> getPrev() {
|
|
+ return prev;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Sets prev link
|
|
+ *
|
|
+ * @param b the previous node
|
|
+ */
|
|
+ void setPrev(Node<E> b) {
|
|
+ prev = b;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns true if this is a header, trailer, or marker node
|
|
+ */
|
|
+ boolean isSpecial() {
|
|
+ return element == null;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns true if this is a trailer node
|
|
+ */
|
|
+ boolean isTrailer() {
|
|
+ return getNext() == null;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns true if this is a header node
|
|
+ */
|
|
+ boolean isHeader() {
|
|
+ return getPrev() == null;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns true if this is a marker node
|
|
+ */
|
|
+ boolean isMarker() {
|
|
+ return getPrev() == this;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns true if this node is followed by a marker, meaning that it is
|
|
+ * deleted.
|
|
+ *
|
|
+ * @return true if this node is deleted
|
|
+ */
|
|
+ boolean isDeleted() {
|
|
+ Node<E> f = getNext();
|
|
+ return f != null && f.isMarker();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns next node, ignoring deletion marker
|
|
+ */
|
|
+ private Node<E> nextNonmarker() {
|
|
+ Node<E> f = getNext();
|
|
+ return (f == null || !f.isMarker()) ? f : f.getNext();
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns the next non-deleted node, swinging next pointer around any
|
|
+ * encountered deleted nodes, and also patching up successor''s prev link to
|
|
+ * point back to this. Returns null if this node is trailer so has no successor.
|
|
+ *
|
|
+ * @return successor, or null if no such
|
|
+ */
|
|
+ Node<E> successor() {
|
|
+ Node<E> f = nextNonmarker();
|
|
+ for (;;) {
|
|
+ if (f == null)
|
|
+ return null;
|
|
+ if (!f.isDeleted()) {
|
|
+ if (f.getPrev() != this && !isDeleted())
|
|
+ f.setPrev(this); // relink f's prev
|
|
+ return f;
|
|
+ }
|
|
+ Node<E> s = f.nextNonmarker();
|
|
+ if (f == getNext())
|
|
+ casNext(f, s); // unlink f
|
|
+ f = s;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns the apparent predecessor of target by searching forward for it
|
|
+ * starting at this node, patching up pointers while traversing. Used by
|
|
+ * predecessor().
|
|
+ *
|
|
+ * @return target's predecessor, or null if not found
|
|
+ */
|
|
+ private Node<E> findPredecessorOf(Node<E> target) {
|
|
+ Node<E> n = this;
|
|
+ for (;;) {
|
|
+ Node<E> f = n.successor();
|
|
+ if (f == target)
|
|
+ return n;
|
|
+ if (f == null)
|
|
+ return null;
|
|
+ n = f;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns the previous non-deleted node, patching up pointers as needed.
|
|
+ * Returns null if this node is header so has no successor. May also return null
|
|
+ * if this node is deleted, so doesn't have a distinct predecessor.
|
|
+ *
|
|
+ * @return predecessor or null if not found
|
|
+ */
|
|
+ Node<E> predecessor() {
|
|
+ Node<E> n = this;
|
|
+ for (;;) {
|
|
+ Node<E> b = n.getPrev();
|
|
+ if (b == null)
|
|
+ return n.findPredecessorOf(this);
|
|
+ Node<E> s = b.getNext();
|
|
+ if (s == this)
|
|
+ return b;
|
|
+ if (s == null || !s.isMarker()) {
|
|
+ Node<E> p = b.findPredecessorOf(this);
|
|
+ if (p != null)
|
|
+ return p;
|
|
+ }
|
|
+ n = b;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns the next node containing a nondeleted user element. Use for forward
|
|
+ * list traversal.
|
|
+ *
|
|
+ * @return successor, or null if no such
|
|
+ */
|
|
+ Node<E> forward() {
|
|
+ Node<E> f = successor();
|
|
+ return (f == null || f.isSpecial()) ? null : f;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns previous node containing a nondeleted user element, if possible. Use
|
|
+ * for backward list traversal, but beware that if this method is called from a
|
|
+ * deleted node, it might not be able to determine a usable predecessor.
|
|
+ *
|
|
+ * @return predecessor, or null if no such could be found
|
|
+ */
|
|
+ Node<E> back() {
|
|
+ Node<E> f = predecessor();
|
|
+ return (f == null || f.isSpecial()) ? null : f;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Tries to insert a node holding element as successor, failing if this node is
|
|
+ * deleted.
|
|
+ *
|
|
+ * @param element the element
|
|
+ * @return the new node, or null on failure.
|
|
+ */
|
|
+ Node<E> append(E element) {
|
|
+ for (;;) {
|
|
+ Node<E> f = getNext();
|
|
+ if (f == null || f.isMarker())
|
|
+ return null;
|
|
+ Node<E> x = new Node<E>(element, f, this);
|
|
+ if (casNext(f, x)) {
|
|
+ f.setPrev(x); // optimistically link
|
|
+ return x;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Tries to insert a node holding element as predecessor, failing if no live
|
|
+ * predecessor can be found to link to.
|
|
+ *
|
|
+ * @param element the element
|
|
+ * @return the new node, or null on failure.
|
|
+ */
|
|
+ Node<E> prepend(E element) {
|
|
+ for (;;) {
|
|
+ Node<E> b = predecessor();
|
|
+ if (b == null)
|
|
+ return null;
|
|
+ Node<E> x = new Node<E>(element, this, b);
|
|
+ if (b.casNext(this, x)) {
|
|
+ setPrev(x); // optimistically link
|
|
+ return x;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Tries to mark this node as deleted, failing if already deleted or if this
|
|
+ * node is header or trailer
|
|
+ *
|
|
+ * @return true if successful
|
|
+ */
|
|
+ boolean delete() {
|
|
+ Node<E> b = getPrev();
|
|
+ Node<E> f = getNext();
|
|
+ if (b != null && f != null && !f.isMarker() && casNext(f, new Node<E>(f))) {
|
|
+ if (b.casNext(this, f))
|
|
+ f.setPrev(b);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Tries to insert a node holding element to replace this node. failing if
|
|
+ * already deleted.
|
|
+ *
|
|
+ * @param newElement the new element
|
|
+ * @return the new node, or null on failure.
|
|
+ */
|
|
+ Node<E> replace(E newElement) {
|
|
+ for (;;) {
|
|
+ Node<E> b = getPrev();
|
|
+ Node<E> f = getNext();
|
|
+ if (b == null || f == null || f.isMarker())
|
|
+ return null;
|
|
+ Node<E> x = new Node<E>(newElement, f, b);
|
|
+ if (casNext(f, new Node<E>(x))) {
|
|
+ b.successor(); // to relink b
|
|
+ x.successor(); // to relink f
|
|
+ return x;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/ConcurrentLongLinkedOpenHashSet.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/ConcurrentLongLinkedOpenHashSet.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..2bf97bd3e77fe4fec785b850524a870300ecd82c
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/ConcurrentLongLinkedOpenHashSet.java
|
|
@@ -0,0 +1,237 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Iterator;
|
|
+import java.util.concurrent.ConcurrentSkipListSet;
|
|
+
|
|
+import it.unimi.dsi.fastutil.longs.LongArrays;
|
|
+import it.unimi.dsi.fastutil.longs.LongCollection;
|
|
+import it.unimi.dsi.fastutil.longs.LongComparator;
|
|
+import it.unimi.dsi.fastutil.longs.LongIterator;
|
|
+import it.unimi.dsi.fastutil.longs.LongIterators;
|
|
+import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
|
|
+import it.unimi.dsi.fastutil.longs.LongListIterator;
|
|
+import it.unimi.dsi.fastutil.longs.LongSortedSet;
|
|
+
|
|
+public class ConcurrentLongLinkedOpenHashSet extends LongLinkedOpenHashSet {
|
|
+
|
|
+ private static final long serialVersionUID = -5532128240738069111L;
|
|
+
|
|
+ private final ConcurrentSkipListSet<Long> backing;
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet() {
|
|
+ //backing = new ConcurrentLinkedDeque<Long>();
|
|
+ backing = new ConcurrentSkipListSet<Long>();
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final int initial) {
|
|
+ //backing = new ConcurrentLinkedDeque<Long>();
|
|
+ backing = new ConcurrentSkipListSet<Long>();
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final int initial, final float dnc) {
|
|
+ this(initial);
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final LongCollection c) {
|
|
+ this(c.size());
|
|
+ addAll(c);
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final LongCollection c, final float f) {
|
|
+ this(c.size(), f);
|
|
+ addAll(c);
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final LongIterator i, final float f) {
|
|
+ this(16, f);
|
|
+ while (i.hasNext())
|
|
+ add(i.nextLong());
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final LongIterator i) {
|
|
+ this(i, -1);
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final Iterator<?> i, final float f) {
|
|
+ this(LongIterators.asLongIterator(i), f);
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final Iterator<?> i) {
|
|
+ this(LongIterators.asLongIterator(i));
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final long[] a, final int offset, final int length, final float f) {
|
|
+ this(length < 0 ? 0 : length, f);
|
|
+ LongArrays.ensureOffsetLength(a, offset, length);
|
|
+ for (int i = 0; i < length; i++)
|
|
+ add(a[offset + i]);
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final long[] a, final int offset, final int length) {
|
|
+ this(a, offset, length, DEFAULT_LOAD_FACTOR);
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final long[] a, final float f) {
|
|
+ this(a, 0, a.length, f);
|
|
+ }
|
|
+
|
|
+ public ConcurrentLongLinkedOpenHashSet(final long[] a) {
|
|
+ this(a, -1);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(final long k) {
|
|
+ boolean out = backing.add(k);
|
|
+ /*
|
|
+ if (!firstDef) {
|
|
+ first = k;
|
|
+ firstDef = true;
|
|
+ }
|
|
+ last = k;
|
|
+ */
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(LongCollection c) {
|
|
+ return addAll((Collection<Long>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends Long> c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAndMoveToFirst(final long k) {
|
|
+ boolean out = backing.add(k);
|
|
+ //first = k;
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAndMoveToLast(final long k) {
|
|
+ boolean out = backing.add(k);
|
|
+ //last = k;
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongLinkedOpenHashSet clone() {
|
|
+ return new ConcurrentLongLinkedOpenHashSet(backing.iterator());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongComparator comparator() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(final long k) {
|
|
+ return backing.contains(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long firstLong() {
|
|
+ /*
|
|
+ if (backing.size() == 0) throw new NoSuchElementException();
|
|
+ return first;
|
|
+ */
|
|
+ return backing.first();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return backing.hashCode();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet headSet(long to) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongListIterator iterator() {
|
|
+ return FastUtilHackUtil.wrap(backing.iterator());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongListIterator iterator(long from) {
|
|
+ throw new IllegalStateException();
|
|
+ //return FastUtilHackUtil.wrap(backing.iterator());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long lastLong() {
|
|
+ /*
|
|
+ if (backing.size() == 0) throw new NoSuchElementException();
|
|
+ return last;
|
|
+ */
|
|
+ return backing.last();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(final long k) {
|
|
+ /*
|
|
+ if (k == first) {
|
|
+ first = backing.iterator().next();
|
|
+ }
|
|
+ if (k == last) {
|
|
+ last = backing.iterator().next();
|
|
+ }
|
|
+ */
|
|
+ return backing.remove(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long removeFirstLong() {
|
|
+ long fl = this.firstLong();
|
|
+ this.remove(fl);
|
|
+ //first = backing.iterator().next();
|
|
+ return fl;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long removeLastLong() {
|
|
+ long fl = this.lastLong();
|
|
+ this.remove(fl);
|
|
+ //last = backing.iterator().next();
|
|
+ return fl;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet subSet(long from, long to) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet tailSet(long from) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean trim() {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean trim(final int n) {
|
|
+ return true;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/ConcurrentLongSortedSet.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/ConcurrentLongSortedSet.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..93bd066ec2013e42a85fcf21344fe41f3ad69598
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/ConcurrentLongSortedSet.java
|
|
@@ -0,0 +1,144 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import it.unimi.dsi.fastutil.longs.*;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.concurrent.ConcurrentSkipListSet;
|
|
+
|
|
+public class ConcurrentLongSortedSet implements LongSortedSet {
|
|
+
|
|
+ ConcurrentSkipListSet<Long> back = new ConcurrentSkipListSet<>();
|
|
+
|
|
+ @Override
|
|
+ public LongBidirectionalIterator iterator(long fromElement) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return back.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return back.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongBidirectionalIterator iterator() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @NotNull
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return back.toArray();
|
|
+ }
|
|
+
|
|
+ @NotNull
|
|
+ @Override
|
|
+ public <T> T[] toArray(@NotNull T[] ts) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(@NotNull Collection<?> collection) {
|
|
+ return back.containsAll(collection);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(@NotNull Collection<? extends Long> collection) {
|
|
+ return back.addAll(collection);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(@NotNull Collection<?> collection) {
|
|
+ return back.removeAll(collection);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(@NotNull Collection<?> collection) {
|
|
+ return back.retainAll(collection);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ back.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(long key) {
|
|
+ return back.add(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(long key) {
|
|
+ return back.contains(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toLongArray() {
|
|
+ return new long[0];
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toArray(long[] a) {
|
|
+ return new long[0];
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(LongCollection c) {
|
|
+ return back.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(LongCollection c) {
|
|
+ return back.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(LongCollection c) {
|
|
+ return back.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(LongCollection c) {
|
|
+ return back.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(long k) {
|
|
+ return back.remove(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet subSet(long fromElement, long toElement) {
|
|
+ return new LongAVLTreeSet(back.subSet(fromElement,toElement));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet headSet(long toElement) {
|
|
+ return new LongAVLTreeSet(back.headSet(toElement));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet tailSet(long fromElement) {
|
|
+ return new LongAVLTreeSet(back.tailSet(fromElement));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongComparator comparator() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long firstLong() {
|
|
+ return back.first();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long lastLong() {
|
|
+ return back.last();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/ConcurrentShortHashSet.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/ConcurrentShortHashSet.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ff1a4f87356459d3bc990a77c3081932046da5b1
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/ConcurrentShortHashSet.java
|
|
@@ -0,0 +1,112 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import it.unimi.dsi.fastutil.shorts.ShortCollection;
|
|
+import it.unimi.dsi.fastutil.shorts.ShortIterator;
|
|
+import it.unimi.dsi.fastutil.shorts.ShortSet;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+
|
|
+public class ConcurrentShortHashSet implements ShortSet {
|
|
+
|
|
+ ConcurrentHashMap.KeySetView<Short, Boolean> backing = ConcurrentHashMap.newKeySet();
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ShortIterator iterator() {
|
|
+ return new FastUtilHackUtil.WrappingShortIterator(backing.iterator());
|
|
+ }
|
|
+
|
|
+ @NotNull
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.toArray();
|
|
+ }
|
|
+
|
|
+ @NotNull
|
|
+ @Override
|
|
+ public <T> T[] toArray(@NotNull T[] ts) {
|
|
+ return (T[]) backing.toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(@NotNull Collection<?> collection) {
|
|
+ return backing.containsAll(collection);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(@NotNull Collection<? extends Short> collection) {
|
|
+ return backing.addAll(collection);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(@NotNull Collection<?> collection) {
|
|
+ return backing.removeAll(collection);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(@NotNull Collection<?> collection) {
|
|
+ return backing.retainAll(collection);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(short key) {
|
|
+ return backing.add(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(short key) {
|
|
+ return backing.contains(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public short[] toShortArray() {
|
|
+ return new short[0];
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public short[] toArray(short[] a) {
|
|
+ return new short[0];
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(ShortCollection c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(ShortCollection c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(ShortCollection c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(ShortCollection c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(short k) {
|
|
+ return backing.remove(k);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/FastUtilHackUtil.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/FastUtilHackUtil.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a14ecb2ca64316fb85e6ecb65df50d98d337aff9
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/FastUtilHackUtil.java
|
|
@@ -0,0 +1,1685 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Iterator;
|
|
+import java.util.LinkedList;
|
|
+import java.util.ListIterator;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
+import java.util.function.Function;
|
|
+import java.util.stream.Collectors;
|
|
+
|
|
+import it.unimi.dsi.fastutil.longs.*;
|
|
+import it.unimi.dsi.fastutil.shorts.ShortIterator;
|
|
+import org.apache.commons.lang3.ArrayUtils;
|
|
+
|
|
+import it.unimi.dsi.fastutil.bytes.ByteCollection;
|
|
+import it.unimi.dsi.fastutil.bytes.ByteIterator;
|
|
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
+import it.unimi.dsi.fastutil.ints.IntCollection;
|
|
+import it.unimi.dsi.fastutil.ints.IntIterator;
|
|
+import it.unimi.dsi.fastutil.ints.IntSet;
|
|
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSet;
|
|
+
|
|
+public class FastUtilHackUtil {
|
|
+
|
|
+ public static class ConvertingObjectSet<E, T> implements ObjectSet<T> {
|
|
+
|
|
+ Set<E> backing;
|
|
+ Function<E, T> forward;
|
|
+ Function<T, E> back;
|
|
+
|
|
+ public ConvertingObjectSet(Set<E> backing, Function<E, T> forward, Function<T, E> back) {
|
|
+ this.backing = backing;
|
|
+ this.forward = forward;
|
|
+ this.back = back;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean contains(Object o) {
|
|
+ try {
|
|
+ return backing.contains(back.apply((T) o));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.stream().map(forward).toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <R> R[] toArray(R[] a) {
|
|
+ return backing.stream().map(forward).collect(Collectors.toSet()).toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(T e) {
|
|
+ return backing.add(back.apply(e));
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean remove(Object o) {
|
|
+ try {
|
|
+ return backing.remove(back.apply((T) o));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ try {
|
|
+ return backing.containsAll(c.stream().map(i -> back.apply((T) i)).collect(Collectors.toSet()));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends T> c) {
|
|
+ return backing.addAll(c.stream().map(i -> back.apply(i)).collect(Collectors.toSet()));
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ try {
|
|
+ return backing.removeAll(c.stream().map(i -> back.apply((T) i)).collect(Collectors.toSet()));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ try {
|
|
+ return backing.retainAll(c.stream().map(i -> back.apply((T) i)).collect(Collectors.toSet()));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectIterator<T> iterator() {
|
|
+ final Iterator<E> backg = backing.iterator();
|
|
+ return new ObjectIterator<T>() {
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return backg.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T next() {
|
|
+ return forward.apply(backg.next());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ backg.remove();
|
|
+ }
|
|
+ };
|
|
+ }
|
|
+
|
|
+
|
|
+ }
|
|
+
|
|
+ public static class ConvertingObjectSetFast<E,T> implements Long2ObjectMap.FastEntrySet<T> {
|
|
+
|
|
+ Set<E> backing;
|
|
+ Function<E, Long2ObjectMap.Entry<T>> forward;
|
|
+ Function<Long2ObjectMap.Entry<T>, E> back;
|
|
+
|
|
+ public ConvertingObjectSetFast(Set<E> backing,
|
|
+ Function<E, Long2ObjectMap.Entry<T>> forward,
|
|
+ Function<Long2ObjectMap.Entry<T>, E> back) {
|
|
+ this.backing = backing;
|
|
+ this.forward = forward;
|
|
+ this.back = back;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean contains(Object o) {
|
|
+ try {
|
|
+ return backing.contains(back.apply((Long2ObjectMap.Entry<T>)o));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.stream().map(forward).toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <R> R[] toArray(R[] a) {
|
|
+ return backing.stream().map(forward).collect(Collectors.toSet()).toArray(a);
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean remove(Object o) {
|
|
+ try {
|
|
+ return backing.remove(back.apply((Long2ObjectMap.Entry<T>)o));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ try {
|
|
+ return backing.containsAll(c.stream()
|
|
+ .map(i -> back.apply((Long2ObjectMap.Entry<T>) i))
|
|
+ .collect(Collectors.toSet()));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ try {
|
|
+ return backing.removeAll(c.stream().map(i -> back
|
|
+ .apply((Long2ObjectMap.Entry<T>) i))
|
|
+ .collect(Collectors.toSet()));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ try {
|
|
+ return backing.retainAll(c.stream()
|
|
+ .map(i -> back.apply((Long2ObjectMap.Entry<T>) i))
|
|
+ .collect(Collectors.toSet()));
|
|
+ } catch (ClassCastException cce) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectIterator<Long2ObjectMap.Entry<T>> iterator() {
|
|
+ final Iterator<E> backg = backing.iterator();
|
|
+ return new ObjectIterator<Long2ObjectMap.Entry<T>>() {
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return backg.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Long2ObjectMap.Entry<T> next() {
|
|
+ return forward.apply(backg.next());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ backg.remove();
|
|
+ }
|
|
+ };
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(Long2ObjectMap.Entry<T> e) {
|
|
+ return backing.add(back.apply(e));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends Long2ObjectMap.Entry<T>> c) {
|
|
+ return backing.addAll(c.stream().map(back).collect(Collectors.toList()));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectIterator<Long2ObjectMap.Entry<T>> fastIterator() {
|
|
+ return iterator();
|
|
+ }
|
|
+
|
|
+
|
|
+ }
|
|
+
|
|
+ private static <T> Entry<T> intEntryForwards(Map.Entry<Integer, T> entry) {
|
|
+ return new Entry<T>() {
|
|
+
|
|
+ @Override
|
|
+ public T getValue() {
|
|
+ return entry.getValue();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T setValue(T value) {
|
|
+ return entry.setValue(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getIntKey() {
|
|
+ return entry.getKey();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(Object obj) {
|
|
+ if (obj == entry) {
|
|
+ return true;
|
|
+ }
|
|
+ return super.equals(obj);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return entry.hashCode();
|
|
+ }
|
|
+ };
|
|
+ }
|
|
+
|
|
+ private static <T> Map.Entry<Integer, T> intEntryBackwards(Entry<T> entry) {
|
|
+ return entry;
|
|
+ }
|
|
+
|
|
+ private static <T> Long2ObjectMap.Entry<T> longEntryForwards(Map.Entry<Long, T> entry) {
|
|
+ return new Long2ObjectMap.Entry<T>() {
|
|
+
|
|
+ @Override
|
|
+ public T getValue() {
|
|
+ return entry.getValue();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T setValue(T value) {
|
|
+ return entry.setValue(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long getLongKey() {
|
|
+ return entry.getKey();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(Object obj) {
|
|
+ if (obj == entry) {
|
|
+ return true;
|
|
+ }
|
|
+ return super.equals(obj);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return entry.hashCode();
|
|
+ }
|
|
+ };
|
|
+ }
|
|
+
|
|
+ private static <T> Map.Entry<Long, T> longEntryBackwards(Long2ObjectMap.Entry<T> entry) {
|
|
+ return entry;
|
|
+ }
|
|
+
|
|
+ private static Long2ByteMap.Entry longByteEntryForwards(Map.Entry<Long, Byte> entry) {
|
|
+ return new Long2ByteMap.Entry() {
|
|
+
|
|
+ @Override
|
|
+ public Byte getValue() {
|
|
+ return entry.getValue();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte setValue(byte value) {
|
|
+ return entry.setValue(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte getByteValue() {
|
|
+ return entry.getValue();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long getLongKey() {
|
|
+ return entry.getKey();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(Object obj) {
|
|
+ if (obj == entry) {
|
|
+ return true;
|
|
+ }
|
|
+ return super.equals(obj);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return entry.hashCode();
|
|
+ }
|
|
+
|
|
+ };
|
|
+ }
|
|
+
|
|
+ private static <T> Map.Entry<Long, Byte> longByteEntryBackwards(Long2ByteMap.Entry entry) {
|
|
+ return entry;
|
|
+ }
|
|
+
|
|
+ private static Long2LongMap.Entry longLongEntryForwards(Map.Entry<Long, Long> entry) {
|
|
+ return new Long2LongMap.Entry() {
|
|
+
|
|
+ @Override
|
|
+ public Long getValue() {
|
|
+ return entry.getValue();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long setValue(long value) {
|
|
+ return entry.setValue(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long getLongValue() {
|
|
+ return entry.getValue();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long getLongKey() {
|
|
+ return entry.getKey();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(Object obj) {
|
|
+ if (obj == entry) {
|
|
+ return true;
|
|
+ }
|
|
+ return super.equals(obj);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return entry.hashCode();
|
|
+ }
|
|
+
|
|
+ };
|
|
+ }
|
|
+
|
|
+ private static <T> Map.Entry<Long, Long> longLongEntryBackwards(Long2LongMap.Entry entry) {
|
|
+ return entry;
|
|
+ }
|
|
+
|
|
+ public static <T> ObjectSet<Entry<T>> entrySetIntWrap(Map<Integer, T> map) {
|
|
+ return new ConvertingObjectSet<Map.Entry<Integer, T>, Entry<T>>(map.entrySet(), FastUtilHackUtil::intEntryForwards, FastUtilHackUtil::intEntryBackwards);
|
|
+ }
|
|
+
|
|
+ public static <T> ObjectSet<Long2ObjectMap.Entry<T>> entrySetLongWrap(Map<Long, T> map) {
|
|
+ return new ConvertingObjectSet<Map.Entry<Long, T>, Long2ObjectMap.Entry<T>>(map.entrySet(), FastUtilHackUtil::longEntryForwards, FastUtilHackUtil::longEntryBackwards);
|
|
+ }
|
|
+
|
|
+ public static <T> Long2ObjectMap.FastEntrySet<T> entrySetLongWrapFast(Map<Long, T> map) {
|
|
+ return new ConvertingObjectSetFast<Map.Entry<Long, T>, T>(map.entrySet(), FastUtilHackUtil::longEntryForwards, FastUtilHackUtil::longEntryBackwards);
|
|
+ }
|
|
+
|
|
+ public static ObjectSet<Long2ByteMap.Entry> entrySetLongByteWrap(Map<Long, Byte> map) {
|
|
+ return new ConvertingObjectSet<Map.Entry<Long, Byte>, Long2ByteMap.Entry>(map.entrySet(), FastUtilHackUtil::longByteEntryForwards, FastUtilHackUtil::longByteEntryBackwards);
|
|
+ }
|
|
+
|
|
+ public static ObjectSet<Long2LongMap.Entry> entrySetLongLongWrap(Map<Long, Long> map) {
|
|
+ return new ConvertingObjectSet<Map.Entry<Long, Long>, Long2LongMap.Entry>(map.entrySet(), FastUtilHackUtil::longLongEntryForwards, FastUtilHackUtil::longLongEntryBackwards);
|
|
+ }
|
|
+
|
|
+
|
|
+ static class WrappingIntIterator implements IntIterator {
|
|
+
|
|
+ Iterator<Integer> backing;
|
|
+
|
|
+ public WrappingIntIterator(Iterator<Integer> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return backing.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int nextInt() {
|
|
+ return backing.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Integer next() {
|
|
+ return backing.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ backing.remove();
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ static class WrappingLongIterator implements LongIterator {
|
|
+
|
|
+ Iterator<Long> backing;
|
|
+
|
|
+ public WrappingLongIterator(Iterator<Long> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return backing.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long nextLong() {
|
|
+ return backing.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Long next() {
|
|
+ return backing.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ backing.remove();
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ static class WrappingShortIterator implements ShortIterator {
|
|
+
|
|
+ Iterator<Short> backing;
|
|
+
|
|
+ public WrappingShortIterator(Iterator<Short> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return backing.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public short nextShort() {
|
|
+ return backing.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Short next() {
|
|
+ return backing.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ backing.remove();
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static class WrappingIntSet implements IntSet {
|
|
+
|
|
+ Set<Integer> backing;
|
|
+
|
|
+ public WrappingIntSet(Set<Integer> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(int key) {
|
|
+ return backing.add(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(int key) {
|
|
+ return backing.contains(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int[] toIntArray() {
|
|
+ return backing.stream().mapToInt(i -> i).toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int[] toIntArray(int[] a) {
|
|
+ if (a.length >= size()) {
|
|
+ return null;
|
|
+ } else {
|
|
+ return toIntArray();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int[] toArray(int[] a) {
|
|
+ return toIntArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(IntCollection c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(IntCollection c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(IntCollection c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(IntCollection c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> T[] toArray(T[] a) {
|
|
+ return backing.toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends Integer> c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public IntIterator iterator() {
|
|
+ return new WrappingIntIterator(backing.iterator());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(int k) {
|
|
+ return backing.remove(k);
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static LongSet wrapLongSet(Set<Long> longset) {
|
|
+ return new WrappingLongSet(longset);
|
|
+ }
|
|
+
|
|
+ public static class WrappingLongSet implements LongSet {
|
|
+
|
|
+ Set<Long> backing;
|
|
+
|
|
+ public WrappingLongSet(Set<Long> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(long key) {
|
|
+ return backing.add(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(long key) {
|
|
+ return backing.contains(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toLongArray() {
|
|
+ return backing.stream().mapToLong(i -> i).toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toLongArray(long[] a) {
|
|
+ if (a.length >= size()) {
|
|
+ return null;
|
|
+ } else {
|
|
+ return toLongArray();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toArray(long[] a) {
|
|
+ return toLongArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(LongCollection c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(LongCollection c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(LongCollection c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(LongCollection c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> T[] toArray(T[] a) {
|
|
+ return backing.toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends Long> c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongIterator iterator() {
|
|
+ return new WrappingLongIterator(backing.iterator());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(long k) {
|
|
+ return backing.remove(k);
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static LongSortedSet wrapLongSortedSet(Set<Long> longset) {
|
|
+ return new WrappingLongSortedSet(longset);
|
|
+ }
|
|
+
|
|
+ public static class WrappingLongSortedSet implements LongSortedSet {
|
|
+
|
|
+ Set<Long> backing;
|
|
+
|
|
+ public WrappingLongSortedSet(Set<Long> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(long key) {
|
|
+ return backing.add(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(long key) {
|
|
+ return backing.contains(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toLongArray() {
|
|
+ return backing.stream().mapToLong(i -> i).toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toLongArray(long[] a) {
|
|
+ if (a.length >= size()) {
|
|
+ return null;
|
|
+ } else {
|
|
+ return toLongArray();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toArray(long[] a) {
|
|
+ return toLongArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(LongCollection c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(LongCollection c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(LongCollection c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(LongCollection c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> T[] toArray(T[] a) {
|
|
+ return backing.toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends Long> c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(long k) {
|
|
+ return backing.remove(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongBidirectionalIterator iterator(long fromElement) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ //return FastUtilHackUtil.wrap(new LinkedList<Long>(backing).iterator());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongBidirectionalIterator iterator() {
|
|
+ return FastUtilHackUtil.wrap(new LinkedList<Long>(backing).iterator());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet subSet(long fromElement, long toElement) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet headSet(long toElement) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet tailSet(long fromElement) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongComparator comparator() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long firstLong() {
|
|
+ return backing.stream().findAny().get();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long lastLong() {
|
|
+ return backing.stream().findAny().get();
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static IntSet wrapIntSet(Set<Integer> intset) {
|
|
+ return new WrappingIntSet(intset);
|
|
+ }
|
|
+
|
|
+ public static class WrappingObjectCollection<V> implements ObjectCollection<V> {
|
|
+
|
|
+ Collection<V> backing;
|
|
+
|
|
+ public WrappingObjectCollection(Collection<V> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(Object o) {
|
|
+ return backing.contains(o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> T[] toArray(T[] a) {
|
|
+ return backing.toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(V e) {
|
|
+ return backing.add(e);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(Object o) {
|
|
+ return backing.remove(o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends V> c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectIterator<V> iterator() {
|
|
+ return FastUtilHackUtil.itrWrap(backing);
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static <K> ObjectCollection<K> wrap(Collection<K> c) {
|
|
+ return new WrappingObjectCollection<K>(c);
|
|
+ }
|
|
+
|
|
+ public static class WrappingByteCollection implements ByteCollection {
|
|
+
|
|
+ Collection<Byte> backing;
|
|
+
|
|
+ public WrappingByteCollection(Collection<Byte> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(byte o) {
|
|
+ return backing.contains(o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> T[] toArray(T[] a) {
|
|
+ return backing.toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(byte e) {
|
|
+ return backing.add(e);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(Object o) {
|
|
+ return backing.remove(o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends Byte> c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ByteIterator iterator() {
|
|
+ return FastUtilHackUtil.itrByteWrap(backing);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean rem(byte key) {
|
|
+ return this.remove(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte[] toByteArray() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte[] toByteArray(byte[] a) {
|
|
+ return toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte[] toArray(byte[] a) {
|
|
+ return ArrayUtils.toPrimitive(backing.toArray(new Byte[0]));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(ByteCollection c) {
|
|
+ return addAll((Collection<Byte>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(ByteCollection c) {
|
|
+ return containsAll((Collection<Byte>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(ByteCollection c) {
|
|
+ return removeAll((Collection<Byte>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(ByteCollection c) {
|
|
+ return retainAll((Collection<Byte>) c);
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static ByteCollection wrapBytes(Collection<Byte> c) {
|
|
+ return new WrappingByteCollection(c);
|
|
+ }
|
|
+
|
|
+ public static class WrappingIntCollection implements IntCollection {
|
|
+
|
|
+ Collection<Integer> backing;
|
|
+
|
|
+ public WrappingIntCollection(Collection<Integer> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(int o) {
|
|
+ return backing.contains(o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> T[] toArray(T[] a) {
|
|
+ return backing.toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(int e) {
|
|
+ return backing.add(e);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(Object o) {
|
|
+ return backing.remove(o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends Integer> c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public IntIterator iterator() {
|
|
+ return FastUtilHackUtil.itrIntWrap(backing);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean rem(int key) {
|
|
+ return this.remove(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int[] toIntArray() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int[] toIntArray(int[] a) {
|
|
+ return toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int[] toArray(int[] a) {
|
|
+ return ArrayUtils.toPrimitive(backing.toArray(new Integer[0]));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(IntCollection c) {
|
|
+ return addAll((Collection<Integer>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(IntCollection c) {
|
|
+ return containsAll((Collection<Integer>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(IntCollection c) {
|
|
+ return removeAll((Collection<Integer>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(IntCollection c) {
|
|
+ return retainAll((Collection<Integer>) c);
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static IntCollection wrapInts(Collection<Integer> c) {
|
|
+ return new WrappingIntCollection(c);
|
|
+ }
|
|
+
|
|
+ public static class WrappingLongCollection implements LongCollection {
|
|
+
|
|
+ Collection<Long> backing;
|
|
+
|
|
+ public WrappingLongCollection(Collection<Long> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean contains(long o) {
|
|
+ return backing.contains(o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object[] toArray() {
|
|
+ return backing.toArray();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public <T> T[] toArray(T[] a) {
|
|
+ return backing.toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean add(long e) {
|
|
+ return backing.add(e);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(Object o) {
|
|
+ return backing.remove(o);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(Collection<?> c) {
|
|
+ return backing.containsAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(Collection<? extends Long> c) {
|
|
+ return backing.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(Collection<?> c) {
|
|
+ return backing.removeAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(Collection<?> c) {
|
|
+ return backing.retainAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongIterator iterator() {
|
|
+ return FastUtilHackUtil.itrLongWrap(backing);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean rem(long key) {
|
|
+ return this.remove(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toLongArray() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toLongArray(long[] a) {
|
|
+ return toArray(a);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long[] toArray(long[] a) {
|
|
+ return ArrayUtils.toPrimitive(backing.toArray(new Long[0]));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean addAll(LongCollection c) {
|
|
+ return addAll((Collection<Long>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsAll(LongCollection c) {
|
|
+ return containsAll((Collection<Long>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean removeAll(LongCollection c) {
|
|
+ return removeAll((Collection<Long>) c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean retainAll(LongCollection c) {
|
|
+ return retainAll((Collection<Long>) c);
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static LongCollection wrapLongs(Collection<Long> c) {
|
|
+ return new WrappingLongCollection(c);
|
|
+ }
|
|
+
|
|
+
|
|
+ public static class WrappingLongListIterator implements LongListIterator {
|
|
+
|
|
+ ListIterator<Long> backing;
|
|
+
|
|
+ public WrappingLongListIterator(ListIterator<Long> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long previousLong() {
|
|
+ return backing.previous();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long nextLong() {
|
|
+ return backing.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return backing.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasPrevious() {
|
|
+ return backing.hasPrevious();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int nextIndex() {
|
|
+ return backing.nextIndex();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int previousIndex() {
|
|
+ return backing.previousIndex();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void add(long k) {
|
|
+ backing.add(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ backing.remove();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void set(long k) {
|
|
+ backing.set(k);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static class SlimWrappingLongListIterator implements LongListIterator {
|
|
+
|
|
+ Iterator<Long> backing;
|
|
+
|
|
+ public SlimWrappingLongListIterator(Iterator<Long> backing) {
|
|
+ this.backing = backing;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long previousLong() {
|
|
+ throw new IllegalStateException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long nextLong() {
|
|
+ return backing.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return backing.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasPrevious() {
|
|
+ throw new IllegalStateException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int nextIndex() {
|
|
+ throw new IllegalStateException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int previousIndex() {
|
|
+ throw new IllegalStateException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void add(long k) {
|
|
+ throw new IllegalStateException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ backing.remove();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void set(long k) {
|
|
+ throw new IllegalStateException();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static LongListIterator wrap(ListIterator<Long> c) {
|
|
+ return new WrappingLongListIterator(c);
|
|
+ }
|
|
+
|
|
+ public static LongListIterator wrap(Iterator<Long> c) {
|
|
+ return new SlimWrappingLongListIterator(c);
|
|
+ }
|
|
+
|
|
+ public static class WrappingByteIterator implements ByteIterator {
|
|
+
|
|
+ Iterator<Byte> parent;
|
|
+
|
|
+ public WrappingByteIterator(Iterator<Byte> parent) {
|
|
+ this.parent = parent;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return parent.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Byte next() {
|
|
+ return parent.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ parent.remove();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte nextByte() {
|
|
+ return next();
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static ByteIterator itrByteWrap(Iterator<Byte> backing) {
|
|
+ return new WrappingByteIterator(backing);
|
|
+ }
|
|
+
|
|
+ public static ByteIterator itrByteWrap(Iterable<Byte> backing) {
|
|
+ return new WrappingByteIterator(backing.iterator());
|
|
+ }
|
|
+
|
|
+ public static IntIterator itrIntWrap(Iterator<Integer> backing) {
|
|
+ return new WrappingIntIterator(backing);
|
|
+ }
|
|
+
|
|
+ public static IntIterator itrIntWrap(Iterable<Integer> backing) {
|
|
+ return new WrappingIntIterator(backing.iterator());
|
|
+ }
|
|
+
|
|
+ public static LongIterator itrLongWrap(Iterator<Long> backing) {
|
|
+ return new WrappingLongIterator(backing);
|
|
+ }
|
|
+
|
|
+ public static LongIterator itrLongWrap(Iterable<Long> backing) {
|
|
+ return new WrappingLongIterator(backing.iterator());
|
|
+ }
|
|
+
|
|
+ public static ShortIterator itrShortWrap(Iterator<Short> backing) {
|
|
+ return new WrappingShortIterator(backing);
|
|
+ }
|
|
+
|
|
+ public static ShortIterator itrShortWrap(Iterable<Short> backing) {
|
|
+ return new WrappingShortIterator(backing.iterator());
|
|
+ }
|
|
+
|
|
+ public static class WrapperObjectIterator<T> implements ObjectIterator<T> {
|
|
+
|
|
+ Iterator<T> parent;
|
|
+
|
|
+ public WrapperObjectIterator(Iterator<T> parent) {
|
|
+ this.parent = parent;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return parent.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T next() {
|
|
+ return parent.next();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ parent.remove();
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static class IntWrapperEntry<T> implements Entry<T> {
|
|
+
|
|
+ Map.Entry<Integer, T> parent;
|
|
+
|
|
+ public IntWrapperEntry(Map.Entry<Integer, T> parent) {
|
|
+ this.parent = parent;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T getValue() {
|
|
+ return parent.getValue();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public T setValue(T value) {
|
|
+ return parent.setValue(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getIntKey() {
|
|
+ return parent.getKey();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Integer getKey() {
|
|
+ return parent.getKey();
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static class Long2IntWrapperEntry implements Long2IntMap.Entry {
|
|
+
|
|
+ Map.Entry<Long, Integer> parent;
|
|
+
|
|
+ public Long2IntWrapperEntry(Map.Entry<Long, Integer> parent) {
|
|
+ this.parent = parent;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long getLongKey() {
|
|
+ return parent.getKey();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getIntValue() {
|
|
+ return parent.getValue();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int setValue(int value) {
|
|
+ return parent.setValue(value);
|
|
+ }
|
|
+
|
|
+
|
|
+ }
|
|
+
|
|
+ public static class WrapperIntEntryObjectIterator<T> implements ObjectIterator<Entry<T>> {
|
|
+
|
|
+ Iterator<Map.Entry<Integer, T>> parent;
|
|
+
|
|
+ public WrapperIntEntryObjectIterator(Iterator<Map.Entry<Integer, T>> parent) {
|
|
+ this.parent = parent;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return parent.hasNext();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Entry<T> next() {
|
|
+ Map.Entry<Integer, T> val = parent.next();
|
|
+ if (val == null) return null;
|
|
+ return new IntWrapperEntry<T>(val);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ parent.remove();
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ public static <T> ObjectIterator<Entry<T>> intMapItrFake(Map<Integer, T> in) {
|
|
+ return new WrapperIntEntryObjectIterator<T>(in.entrySet().iterator());
|
|
+ }
|
|
+
|
|
+ public static <T> ObjectIterator<T> itrWrap(Iterator<T> in) {
|
|
+ return new WrapperObjectIterator<T>(in);
|
|
+ }
|
|
+
|
|
+ public static <T> ObjectIterator<T> itrWrap(Iterable<T> in) {
|
|
+ return new WrapperObjectIterator<T>(in.iterator());
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Int2ObjectConcurrentHashMap.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Int2ObjectConcurrentHashMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..bb6c592fd34423fdd910feae83a058d288da537a
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Int2ObjectConcurrentHashMap.java
|
|
@@ -0,0 +1,93 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
+import it.unimi.dsi.fastutil.ints.IntSet;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSet;
|
|
+import org.apache.commons.lang3.NotImplementedException;
|
|
+
|
|
+import java.util.Map;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+
|
|
+public class Int2ObjectConcurrentHashMap<V> implements Int2ObjectMap<V> {
|
|
+
|
|
+ Map<Integer, V> backing;
|
|
+
|
|
+ public Int2ObjectConcurrentHashMap() {
|
|
+ backing = new ConcurrentHashMap<Integer, V>();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V get(int key) {
|
|
+ return backing.get(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsValue(Object value) {
|
|
+ return backing.containsValue(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void putAll(Map<? extends Integer, ? extends V> m) {
|
|
+ backing.putAll(m);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void defaultReturnValue(V rv) {
|
|
+ throw new NotImplementedException("MCMT - Not implemented");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V defaultReturnValue() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectSet<Entry<V>> int2ObjectEntrySet() {
|
|
+ return FastUtilHackUtil.entrySetIntWrap(backing);
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public IntSet keySet() {
|
|
+ return FastUtilHackUtil.wrapIntSet(backing.keySet());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectCollection<V> values() {
|
|
+ return FastUtilHackUtil.wrap(backing.values());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsKey(int key) {
|
|
+ return backing.containsKey(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V put(int key, V value) {
|
|
+ return backing.put(key, value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V put(Integer key, V value) {
|
|
+ return backing.put(key, value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V remove(int key) {
|
|
+ return backing.remove(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() { backing.clear(); }
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2ByteConcurrentHashMap.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2ByteConcurrentHashMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..e0fab16860e1be817fd10dbec684f295f2e291dd
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2ByteConcurrentHashMap.java
|
|
@@ -0,0 +1,99 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import it.unimi.dsi.fastutil.bytes.ByteCollection;
|
|
+import it.unimi.dsi.fastutil.longs.Long2ByteMap;
|
|
+import it.unimi.dsi.fastutil.longs.LongSet;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSet;
|
|
+
|
|
+import java.util.Map;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+
|
|
+public class Long2ByteConcurrentHashMap implements Long2ByteMap {
|
|
+
|
|
+ Map<Long, Byte> backing;
|
|
+ byte defaultReturn = 0;
|
|
+ byte nullKey = 0;
|
|
+
|
|
+ public Long2ByteConcurrentHashMap() {
|
|
+ backing = new ConcurrentHashMap<>();
|
|
+ }
|
|
+
|
|
+ public Long2ByteConcurrentHashMap(int initialCapacity, float loadFactor) {
|
|
+ backing = new ConcurrentHashMap<>(initialCapacity, loadFactor);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte get(long key) {
|
|
+ Byte out = backing.get(key);
|
|
+ return out == null ? defaultReturn : out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsValue(byte value) {
|
|
+ return backing.containsValue(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void putAll(Map<? extends Long, ? extends Byte> m) {
|
|
+ backing.putAll(m);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void defaultReturnValue(byte rv) {
|
|
+ defaultReturn = rv;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte defaultReturnValue() {
|
|
+ return defaultReturn;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectSet<Entry> long2ByteEntrySet() {
|
|
+ return FastUtilHackUtil.entrySetLongByteWrap(backing);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSet keySet() {
|
|
+ return FastUtilHackUtil.wrapLongSet(backing.keySet());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ByteCollection values() {
|
|
+ return FastUtilHackUtil.wrapBytes(backing.values());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsKey(long key) {
|
|
+ return backing.containsKey(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte put(long key, byte value) {
|
|
+ return put((Long) key, (Byte) value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Byte put(Long key, Byte value) {
|
|
+ Byte out = backing.put(key, value);
|
|
+ return out == null ? Byte.valueOf(defaultReturn) : out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public byte remove(long key) {
|
|
+ Byte out = backing.remove(key);
|
|
+ return out == null ? defaultReturn : out;
|
|
+ }
|
|
+
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2IntConcurrentHashMap.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2IntConcurrentHashMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..261f06a88021a95b6a0500444665547aeb4ae2c1
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2IntConcurrentHashMap.java
|
|
@@ -0,0 +1,74 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import it.unimi.dsi.fastutil.ints.IntCollection;
|
|
+import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
|
+import it.unimi.dsi.fastutil.longs.LongSet;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSet;
|
|
+
|
|
+import java.util.Map;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+
|
|
+public class Long2IntConcurrentHashMap implements Long2IntMap {
|
|
+
|
|
+ public Map<Long, Integer> backing = new ConcurrentHashMap<Long, Integer>();
|
|
+ int defaultRV = 0;
|
|
+
|
|
+ @Override
|
|
+ public int get(long key) {
|
|
+ if (backing.containsKey(key)) {
|
|
+ return backing.get(key);
|
|
+ } else return defaultRV;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void putAll(Map<? extends Long, ? extends Integer> m) {
|
|
+ backing.putAll(m);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void defaultReturnValue(int rv) {
|
|
+ defaultRV = rv;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int defaultReturnValue() {
|
|
+ return defaultRV;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectSet<Entry> long2IntEntrySet() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSet keySet() {
|
|
+ return FastUtilHackUtil.wrapLongSet(backing.keySet());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public IntCollection values() {
|
|
+ return FastUtilHackUtil.wrapInts(backing.values());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsKey(long key) {
|
|
+ return backing.containsKey(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsValue(int value) {
|
|
+ return backing.containsValue(value);
|
|
+ }
|
|
+
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2IntConcurrentNonLinkedOpenMap.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2IntConcurrentNonLinkedOpenMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..dc2342486318721d399c7c60a0a859befb4d1c9f
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2IntConcurrentNonLinkedOpenMap.java
|
|
@@ -0,0 +1,375 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import it.unimi.dsi.fastutil.Hash;
|
|
+import it.unimi.dsi.fastutil.ints.IntCollection;
|
|
+import it.unimi.dsi.fastutil.longs.*;
|
|
+
|
|
+import java.util.Map;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+
|
|
+@SuppressWarnings("deprecation")
|
|
+public class Long2IntConcurrentNonLinkedOpenMap extends Long2IntLinkedOpenHashMap {
|
|
+
|
|
+ /**
|
|
+ *
|
|
+ */
|
|
+ private static final long serialVersionUID = -2082212127278131631L;
|
|
+
|
|
+ public Map<Long, Integer> backing = new ConcurrentHashMap<Long, Integer>();
|
|
+
|
|
+ public Long2IntConcurrentNonLinkedOpenMap(final int expected, final float f) {
|
|
+
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
|
|
+ *
|
|
+ * @param expected the expected number of elements in the hash map.
|
|
+ */
|
|
+ public Long2IntConcurrentNonLinkedOpenMap(final int expected) {
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates a new hash map with initial expected
|
|
+ * {@link Hash#DEFAULT_INITIAL_SIZE} entries and
|
|
+ * {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
|
|
+ */
|
|
+ public Long2IntConcurrentNonLinkedOpenMap() {
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates a new hash map copying a given one.
|
|
+ *
|
|
+ * @param m a {@link Map} to be copied into the new hash map.
|
|
+ * @param f the load factor.
|
|
+ */
|
|
+ public Long2IntConcurrentNonLinkedOpenMap(final Map<? extends Long, ? extends Integer> m, final float f) {
|
|
+ putAll(m);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor
|
|
+ * copying a given one.
|
|
+ *
|
|
+ * @param m a {@link Map} to be copied into the new hash map.
|
|
+ */
|
|
+ public Long2IntConcurrentNonLinkedOpenMap(final Map<? extends Long, ? extends Integer> m) {
|
|
+ this(m, DEFAULT_LOAD_FACTOR);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates a new hash map copying a given type-specific one.
|
|
+ *
|
|
+ * @param m a type-specific map to be copied into the new hash map.
|
|
+ * @param f the load factor.
|
|
+ */
|
|
+ public Long2IntConcurrentNonLinkedOpenMap(final Long2IntMap m, final float f) {
|
|
+ this(m.size(), f);
|
|
+ putAll(m);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor
|
|
+ * copying a given type-specific one.
|
|
+ *
|
|
+ * @param m a type-specific map to be copied into the new hash map.
|
|
+ */
|
|
+ public Long2IntConcurrentNonLinkedOpenMap(final Long2IntMap m) {
|
|
+ this(m, DEFAULT_LOAD_FACTOR);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates a new hash map using the elements of two parallel arrays.
|
|
+ *
|
|
+ * @param k the array of keys of the new hash map.
|
|
+ * @param v the array of corresponding values in the new hash map.
|
|
+ * @param f the load factor.
|
|
+ * @throws IllegalArgumentException if {@code k} and {@code v} have different
|
|
+ * lengths.
|
|
+ */
|
|
+ public Long2IntConcurrentNonLinkedOpenMap(final long[] k, final int[] v, final float f) {
|
|
+ if (k.length != v.length)
|
|
+ throw new IllegalArgumentException(
|
|
+ "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")");
|
|
+ for (int i = 0; i < k.length; i++)
|
|
+ this.put(k[i], v[i]);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor
|
|
+ * using the elements of two parallel arrays.
|
|
+ *
|
|
+ * @param k the array of keys of the new hash map.
|
|
+ * @param v the array of corresponding values in the new hash map.
|
|
+ * @throws IllegalArgumentException if {@code k} and {@code v} have different
|
|
+ * lengths.
|
|
+ */
|
|
+ public Long2IntConcurrentNonLinkedOpenMap(final long[] k, final int[] v) {
|
|
+ this(k, v, DEFAULT_LOAD_FACTOR);
|
|
+ }
|
|
+
|
|
+ public void putAll(Map<? extends Long, ? extends Integer> m) {
|
|
+ backing.putAll(m);
|
|
+ }
|
|
+
|
|
+ public int put(final long k, final int v) {
|
|
+ Integer out = backing.put(k, v);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public int addTo(final long k, final int incr) {
|
|
+ Integer out = backing.put(k, this.get(k)+incr);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public int remove(final long k) {
|
|
+ Integer out = backing.remove(k);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public int removeFirstInt() {
|
|
+ Integer out = this.remove(backing.keySet().stream().findAny().get());
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public int removeLastInt() {
|
|
+ Integer out = this.remove(backing.keySet().stream().findAny().get());
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+
|
|
+ public int getAndMoveToFirst(final long k) {
|
|
+ Integer out = backing.get(k);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public int getAndMoveToLast(final long k) {
|
|
+ Integer out = backing.get(k);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public int putAndMoveToFirst(final long k, final int v) {
|
|
+ Integer out = backing.put(k, v);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public int putAndMoveToLast(final long k, final int v) {
|
|
+ Integer out = backing.put(k, v);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public int get(final long k) {
|
|
+ Integer out = backing.get(k);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public boolean containsKey(final long k) {
|
|
+ return backing.containsKey(k);
|
|
+ }
|
|
+
|
|
+ public boolean containsValue(final int v) {
|
|
+ return backing.containsValue(v);
|
|
+ }
|
|
+
|
|
+ public int getOrDefault(final long k, final int defaultValue) {
|
|
+ Integer out = backing.getOrDefault(k, defaultValue);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ public int putIfAbsent(final long k, final int v) {
|
|
+ Integer out = backing.putIfAbsent(k, v);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+
|
|
+ public boolean remove(final long k, final int v) {
|
|
+ return backing.remove(k, v);
|
|
+ }
|
|
+
|
|
+
|
|
+ public boolean replace(final long k, final int oldValue, final int v) {
|
|
+ return backing.replace(k, oldValue, v);
|
|
+ }
|
|
+
|
|
+
|
|
+ public int replace(final long k, final int v) {
|
|
+ Integer out = backing.replace(k, v);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+
|
|
+ public int computeIfAbsent(final long k, final java.util.function.LongToIntFunction mappingFunction) {
|
|
+ Integer out = backing.computeIfAbsent(k, (l) -> mappingFunction.applyAsInt(l));
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+
|
|
+ public int computeIfAbsentNullable(final long k,
|
|
+ final java.util.function.LongFunction<? extends Integer> mappingFunction) {
|
|
+ Integer out = backing.computeIfAbsent(k, (l) -> mappingFunction.apply(l));
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+
|
|
+ public int computeIfPresent(final long k,
|
|
+ final java.util.function.BiFunction<? super Long, ? super Integer, ? extends Integer> remappingFunction) {
|
|
+ if (this.containsKey(k)) {
|
|
+ Integer out = backing.put(k, remappingFunction.apply(k, backing.get(k)));
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+ return defaultReturnValue();
|
|
+
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int compute(final long k,
|
|
+ final java.util.function.BiFunction<? super Long, ? super Integer, ? extends Integer> remappingFunction) {
|
|
+ Integer out = backing.compute(k, remappingFunction);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int merge(final long k, final int v,
|
|
+ final java.util.function.BiFunction<? super Integer, ? super Integer, ? extends Integer> remappingFunction) {
|
|
+ Integer out = backing.merge(k, v, remappingFunction);
|
|
+ if (out == null) {
|
|
+ return defRetValue;
|
|
+ }
|
|
+ return out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long firstLongKey() {
|
|
+ return backing.keySet().stream().findAny().get();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long lastLongKey() {
|
|
+ return backing.keySet().stream().findAny().get();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Long2IntSortedMap tailMap(long from) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Long2IntSortedMap headMap(long to) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Long2IntSortedMap subMap(long from, long to) {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongComparator comparator() {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public FastSortedEntrySet long2IntEntrySet() {
|
|
+ //TODO implement
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongSortedSet keySet() {
|
|
+ return FastUtilHackUtil.wrapLongSortedSet(backing.keySet());
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public IntCollection values() {
|
|
+ return FastUtilHackUtil.wrapInts(backing.values());
|
|
+ }
|
|
+
|
|
+ public boolean trim() {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ public boolean trim(final int n) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public Long2IntConcurrentNonLinkedOpenMap clone() {
|
|
+ return new Long2IntConcurrentNonLinkedOpenMap(backing);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return backing.hashCode();
|
|
+ }
|
|
+
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2LongConcurrentHashMap.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2LongConcurrentHashMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..3205d30a03f99caf7dfa05237b2bc31182b2db20
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2LongConcurrentHashMap.java
|
|
@@ -0,0 +1,97 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import it.unimi.dsi.fastutil.longs.Long2LongMap;
|
|
+import it.unimi.dsi.fastutil.longs.LongCollection;
|
|
+import it.unimi.dsi.fastutil.longs.LongSet;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSet;
|
|
+
|
|
+import java.util.Map;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+
|
|
+
|
|
+public class Long2LongConcurrentHashMap implements Long2LongMap {
|
|
+
|
|
+ public Map<Long, Long> backing = new ConcurrentHashMap<Long, Long>();
|
|
+ long defaultRV = 0;
|
|
+
|
|
+ public Long2LongConcurrentHashMap(long defaultRV) {
|
|
+ this.defaultRV = defaultRV;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long get(long key) {
|
|
+ if (backing.containsKey(key)) {
|
|
+ return backing.get(key);
|
|
+ } else return defaultRV;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long put(final long key, final long val) {
|
|
+ backing.put(key,val);
|
|
+ return val;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Long put(final Long key, final Long val) {
|
|
+ backing.put(key,val);
|
|
+ return val;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long remove(final long key) {
|
|
+ return backing.remove(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void putAll(Map<? extends Long, ? extends Long> m) {
|
|
+ backing.putAll(m);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void defaultReturnValue(long rv) {
|
|
+ defaultRV = rv;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public long defaultReturnValue() {
|
|
+ return defaultRV;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectSet<Entry> long2LongEntrySet() {
|
|
+ return FastUtilHackUtil.entrySetLongLongWrap(backing);
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public LongSet keySet() {
|
|
+ return FastUtilHackUtil.wrapLongSet(backing.keySet());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LongCollection values() {
|
|
+ return FastUtilHackUtil.wrapLongs(backing.values());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsKey(long key) {
|
|
+ return backing.containsKey(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsValue(long value) {
|
|
+ return backing.containsValue(value);
|
|
+ }
|
|
+
|
|
+
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2ObjectConcurrentHashMap.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2ObjectConcurrentHashMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a5ed71564d4c9a986f77cbc0397130aa38f97a91
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2ObjectConcurrentHashMap.java
|
|
@@ -0,0 +1,93 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
|
+import it.unimi.dsi.fastutil.longs.LongSet;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSet;
|
|
+
|
|
+import java.util.Map;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+
|
|
+public class Long2ObjectConcurrentHashMap<V> implements Long2ObjectMap<V> {
|
|
+
|
|
+ Map<Long, V> backing;
|
|
+ V defaultReturn = null;
|
|
+
|
|
+ public Long2ObjectConcurrentHashMap() {
|
|
+ backing = new ConcurrentHashMap<Long, V>();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V get(long key) {
|
|
+ V out = backing.get(key);
|
|
+ return (out == null && !backing.containsKey(key)) ? defaultReturn : out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsValue(Object value) {
|
|
+ return backing.containsValue(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void putAll(Map<? extends Long, ? extends V> m) {
|
|
+ backing.putAll(m);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void defaultReturnValue(V rv) {
|
|
+ defaultReturn = rv;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V defaultReturnValue() {
|
|
+ return defaultReturn;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectSet<Entry<V>> long2ObjectEntrySet() {
|
|
+ return FastUtilHackUtil.entrySetLongWrap(backing);
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public LongSet keySet() {
|
|
+ return FastUtilHackUtil.wrapLongSet(backing.keySet());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectCollection<V> values() {
|
|
+ return FastUtilHackUtil.wrap(backing.values());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsKey(long key) {
|
|
+ return backing.containsKey(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V put(long key, V value) {
|
|
+ return put((Long)key, value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V put(Long key, V value) {
|
|
+ V out = backing.put(key, value);
|
|
+ return (out == null && !backing.containsKey(key)) ? defaultReturn : backing.put(key, value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V remove(long key) {
|
|
+ V out = backing.remove(key);
|
|
+ return (out == null && !backing.containsKey(key)) ? defaultReturn : out;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2ObjectOpenConcurrentHashMap.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2ObjectOpenConcurrentHashMap.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a7d6be048ab3b8bd38231fce16eca0ac78e24690
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/Long2ObjectOpenConcurrentHashMap.java
|
|
@@ -0,0 +1,233 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil;
|
|
+
|
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectFunction;
|
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|
+import it.unimi.dsi.fastutil.longs.LongSet;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSet;
|
|
+
|
|
+import java.util.Map;
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
+import java.util.function.Function;
|
|
+
|
|
+public class Long2ObjectOpenConcurrentHashMap<V> extends Long2ObjectOpenHashMap<V> {
|
|
+
|
|
+ /**
|
|
+ *
|
|
+ */
|
|
+ private static final long serialVersionUID = -121514116954680057L;
|
|
+
|
|
+ Map<Long, V> backing;
|
|
+ V defaultReturn = null;
|
|
+
|
|
+ public Long2ObjectOpenConcurrentHashMap() {
|
|
+ backing = new ConcurrentHashMap<Long, V>();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V get(long key) {
|
|
+ V out = backing.get(key);
|
|
+ return (out == null && !backing.containsKey(key)) ? defaultReturn : out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V get(Object key) {
|
|
+ V out = backing.get(key);
|
|
+ return (out == null && !backing.containsKey(key)) ? defaultReturn : out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isEmpty() {
|
|
+ return backing.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsValue(Object value) {
|
|
+ return backing.containsValue(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void putAll(Map<? extends Long, ? extends V> m) {
|
|
+ backing.putAll(m);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int size() {
|
|
+ return backing.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void defaultReturnValue(V rv) {
|
|
+ defaultReturn = rv;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V defaultReturnValue() {
|
|
+ return defaultReturn;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public FastEntrySet<V> long2ObjectEntrySet() {
|
|
+ return FastUtilHackUtil.entrySetLongWrapFast(backing);
|
|
+ }
|
|
+
|
|
+
|
|
+ @Override
|
|
+ public LongSet keySet() {
|
|
+ return FastUtilHackUtil.wrapLongSet(backing.keySet());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectCollection<V> values() {
|
|
+ return FastUtilHackUtil.wrap(backing.values());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean containsKey(long key) {
|
|
+ return backing.containsKey(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V put(long key, V value) {
|
|
+ return put((Long)key, value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V put(Long key, V value) {
|
|
+ V out = backing.put(key, value);
|
|
+ return (out == null && !backing.containsKey(key)) ? defaultReturn : backing.put(key, value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V remove(long key) {
|
|
+ V out = backing.remove(key);
|
|
+ return (out == null && !backing.containsKey(key)) ? defaultReturn : out;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean trim() { return true; }
|
|
+
|
|
+ @Override
|
|
+ public boolean trim(final int n) { return true; }
|
|
+
|
|
+ @Override
|
|
+ public boolean replace(final long k, final V oldValue, final V v) {
|
|
+ return backing.replace(k, oldValue, v);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V replace(final long k, final V v) {
|
|
+ return backing.replace(k, v);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean replace(final Long k, final V oldValue, final V v) {
|
|
+ return backing.replace(k, oldValue, v);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V replace(final Long k, final V v) {
|
|
+ return backing.replace(k, v);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(final long k, final Object v) {
|
|
+ return backing.remove(k, v);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V putIfAbsent(final long k, final V v) {
|
|
+ return backing.putIfAbsent(k, v);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V putIfAbsent(final Long k, final V v) {
|
|
+ return backing.putIfAbsent(k, v);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V merge(final long k, final V v, final java.util.function.BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
|
|
+ return backing.merge(k, v, remappingFunction);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V merge(Long k, final V v, final java.util.function.BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
|
|
+ return backing.merge(k, v, remappingFunction);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return backing.hashCode();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V getOrDefault(final long k, final V defaultValue) {
|
|
+ return backing.getOrDefault(k, defaultValue);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V getOrDefault(Object k, final V defaultValue) {
|
|
+ return backing.getOrDefault(k, defaultValue);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V computeIfPresent(final long k, final java.util.function.BiFunction<? super Long, ? super V, ? extends V> remappingFunction) {
|
|
+ return backing.computeIfPresent(k, remappingFunction);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V computeIfPresent(final Long k, final java.util.function.BiFunction<? super Long, ? super V, ? extends V> remappingFunction) {
|
|
+ return backing.computeIfPresent(k, remappingFunction);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V computeIfAbsent(final long k, final java.util.function.LongFunction<? extends V> mappingFunction) {
|
|
+ return backing.computeIfAbsent(k, (llong) -> mappingFunction.apply(llong));
|
|
+ }
|
|
+
|
|
+ public V computeIfAbsent(final Long k, final java.util.function.LongFunction<? extends V> mappingFunction) {
|
|
+ return backing.computeIfAbsent(k, (llong) -> mappingFunction.apply(llong));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V computeIfAbsentPartial(final long key, final Long2ObjectFunction<? extends V> mappingFunction) {
|
|
+ if (!mappingFunction.containsKey(key))
|
|
+ return defaultReturn;
|
|
+ return backing.computeIfAbsent(key, (llong) -> mappingFunction.apply(llong));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V compute(final long k, final java.util.function.BiFunction<? super Long, ? super V, ? extends V> remappingFunction) {
|
|
+ return backing.compute(k, remappingFunction);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V compute(final Long k, final java.util.function.BiFunction<? super Long, ? super V, ? extends V> remappingFunction) {
|
|
+ return backing.compute(k, remappingFunction);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Long2ObjectOpenHashMap<V> clone() {
|
|
+ throw new IllegalArgumentException();
|
|
+ }
|
|
+
|
|
+ public void clear() {
|
|
+ backing.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ObjectSet<Map.Entry<Long, V>> entrySet() {
|
|
+ return new FastUtilHackUtil.ConvertingObjectSet<Map.Entry<Long, V>, Map.Entry<Long, V>>(backing.entrySet(), Function.identity(), Function.identity());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public V remove(Object key) {
|
|
+ return backing.remove(key);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean remove(Object key, Object value) {
|
|
+ return backing.remove(key, value);
|
|
+ }
|
|
+
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/sync/SyncLongLinkedOpenHashSet.java b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/sync/SyncLongLinkedOpenHashSet.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..565dc74cb65ef0ce9df36a72d9cd5fa440a535e6
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/himeki/mcmtfabric/parallelised/fastutil/sync/SyncLongLinkedOpenHashSet.java
|
|
@@ -0,0 +1,197 @@
|
|
+package net.himeki.mcmtfabric.parallelised.fastutil.sync;
|
|
+
|
|
+import java.util.Collection;
|
|
+import java.util.Iterator;
|
|
+
|
|
+import it.unimi.dsi.fastutil.longs.LongArrays;
|
|
+import it.unimi.dsi.fastutil.longs.LongCollection;
|
|
+import it.unimi.dsi.fastutil.longs.LongComparator;
|
|
+import it.unimi.dsi.fastutil.longs.LongIterator;
|
|
+import it.unimi.dsi.fastutil.longs.LongIterators;
|
|
+import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
|
|
+import it.unimi.dsi.fastutil.longs.LongListIterator;
|
|
+import it.unimi.dsi.fastutil.longs.LongSortedSet;
|
|
+
|
|
+public class SyncLongLinkedOpenHashSet extends LongLinkedOpenHashSet {
|
|
+
|
|
+ private static final long serialVersionUID = -5532128240738069111L;
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet() {
|
|
+ super();
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final int initial) {
|
|
+ super(initial);
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final int initial, final float dnc) {
|
|
+ this(initial);
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final LongCollection c) {
|
|
+ this(c.size());
|
|
+ addAll(c);
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final LongCollection c, final float f) {
|
|
+ this(c.size(), f);
|
|
+ addAll(c);
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final LongIterator i, final float f) {
|
|
+ this(16, f);
|
|
+ while (i.hasNext())
|
|
+ add(i.nextLong());
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final LongIterator i) {
|
|
+ this(i, -1);
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final Iterator<?> i, final float f) {
|
|
+ this(LongIterators.asLongIterator(i), f);
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final Iterator<?> i) {
|
|
+ this(LongIterators.asLongIterator(i));
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final long[] a, final int offset, final int length, final float f) {
|
|
+ this(length < 0 ? 0 : length, f);
|
|
+ LongArrays.ensureOffsetLength(a, offset, length);
|
|
+ for (int i = 0; i < length; i++)
|
|
+ add(a[offset + i]);
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final long[] a, final int offset, final int length) {
|
|
+ this(a, offset, length, DEFAULT_LOAD_FACTOR);
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final long[] a, final float f) {
|
|
+ this(a, 0, a.length, f);
|
|
+ }
|
|
+
|
|
+ public SyncLongLinkedOpenHashSet(final long[] a) {
|
|
+ this(a, -1);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean add(final long k) {
|
|
+ return super.add(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean addAll(LongCollection c) {
|
|
+ return super.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean addAll(Collection<? extends Long> c) {
|
|
+ return super.addAll(c);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean addAndMoveToFirst(final long k) {
|
|
+ return super.addAndMoveToFirst(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean addAndMoveToLast(final long k) {
|
|
+ return super.addAndMoveToFirst(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized void clear() {
|
|
+ super.clear();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized LongLinkedOpenHashSet clone() {
|
|
+ return new SyncLongLinkedOpenHashSet(this);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized LongComparator comparator() {
|
|
+ return super.comparator();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean contains(final long k) {
|
|
+ return super.contains(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized long firstLong() {
|
|
+ return super.firstLong();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized int hashCode() {
|
|
+ return super.hashCode();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized LongSortedSet headSet(long to) {
|
|
+ return super.headSet(to);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean isEmpty() {
|
|
+ return super.isEmpty();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized LongListIterator iterator() {
|
|
+ return super.iterator();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized LongListIterator iterator(long from) {
|
|
+ return super.iterator(from);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized long lastLong() {
|
|
+ return super.lastLong();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean remove(final long k) {
|
|
+ return super.remove(k);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized long removeFirstLong() {
|
|
+ return super.removeFirstLong();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized long removeLastLong() {
|
|
+ return super.removeLastLong();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized int size() {
|
|
+ return super.size();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized LongSortedSet subSet(long from, long to) {
|
|
+ return super.subSet(from, to);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized LongSortedSet tailSet(long from) {
|
|
+ return super.tailSet(from);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean trim() {
|
|
+ return super.trim();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public synchronized boolean trim(final int n) {
|
|
+ return super.trim(n);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
|
index 24c677e80af652952263253409c050641e72e3b5..39ace58ad7560d9339ea97230ee5c3ddef6cdc7d 100644
|
|
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
|
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
|
@@ -2,6 +2,9 @@ package net.minecraft.network.protocol.game;
|
|
|
|
import it.unimi.dsi.fastutil.shorts.ShortIterator;
|
|
import it.unimi.dsi.fastutil.shorts.ShortSet;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
import java.util.function.BiConsumer;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.SectionPos;
|
|
@@ -22,16 +25,18 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet<ClientGamePa
|
|
public ClientboundSectionBlocksUpdatePacket(SectionPos sectionPos, ShortSet positions, LevelChunkSection section, boolean noLightingUpdates) {
|
|
this.sectionPos = sectionPos;
|
|
this.suppressLightUpdates = noLightingUpdates;
|
|
- int i = positions.size();
|
|
|
|
- this.positions = new short[i];
|
|
- this.states = new BlockState[i];
|
|
- int j = 0;
|
|
-
|
|
- for (ShortIterator shortiterator = positions.iterator(); shortiterator.hasNext(); ++j) {
|
|
- short short0 = (Short) shortiterator.next();
|
|
+ final List<Short> copy = new ArrayList<>(positions);
|
|
+ this.positions = new short[copy.size()];
|
|
+ int counter = 0;
|
|
+ for (Short s : copy){
|
|
+ this.positions[counter] = s;
|
|
+ counter++;
|
|
+ }
|
|
+ this.states = new BlockState[this.positions.length];
|
|
|
|
- this.positions[j] = short0;
|
|
+ for (int j = 0;j < this.positions.length; ++j) {
|
|
+ short short0 = this.positions[j];
|
|
this.states[j] = (section != null) ? section.getBlockState(SectionPos.sectionRelativeX(short0), SectionPos.sectionRelativeY(short0), SectionPos.sectionRelativeZ(short0)) : net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(); // CraftBukkit - SPIGOT-6076, Mojang bug when empty chunk section notified
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index 3b7e4b724e86518ea57f5ed5ef0b8b3741d10f6f..56a24216cfb635c77f02e3b5e248ecc699454691 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -1,10 +1,10 @@
|
|
package net.minecraft.server;
|
|
|
|
+import co.aikar.timings.MinecraftTimings;
|
|
+import co.m2ek4u.hearse.ForkJoinTickThread;
|
|
+import co.m2ek4u.hearse.HearseConfig;
|
|
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;
|
|
@@ -12,59 +12,17 @@ import com.mojang.authlib.GameProfile;
|
|
import com.mojang.authlib.GameProfileRepository;
|
|
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
|
import com.mojang.datafixers.DataFixer;
|
|
+import com.mojang.datafixers.util.Pair;
|
|
import com.mojang.logging.LogUtils;
|
|
+import com.mojang.serialization.DynamicOps;
|
|
+import com.mojang.serialization.Lifecycle;
|
|
import it.unimi.dsi.fastutil.longs.LongIterator;
|
|
-import java.awt.image.BufferedImage;
|
|
-import java.io.BufferedWriter;
|
|
-import java.io.ByteArrayOutputStream;
|
|
-import java.io.File;
|
|
-import java.io.IOException;
|
|
-import java.lang.management.ManagementFactory;
|
|
-import java.lang.management.ThreadInfo;
|
|
-import java.lang.management.ThreadMXBean;
|
|
-import java.net.Proxy;
|
|
-import java.nio.charset.StandardCharsets;
|
|
-import java.nio.file.Files;
|
|
-import java.nio.file.Path;
|
|
-import java.security.KeyPair;
|
|
-import java.util.ArrayList;
|
|
-import java.util.Arrays;
|
|
-import java.util.Base64;
|
|
-import java.util.Collection;
|
|
-import java.util.Collections;
|
|
-import java.util.Comparator;
|
|
-import java.util.Iterator;
|
|
-import java.util.List;
|
|
-import java.util.Locale;
|
|
-import java.util.Map;
|
|
-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.atomic.AtomicReference;
|
|
-import java.util.function.BooleanSupplier;
|
|
-import java.util.function.Consumer;
|
|
-import java.util.function.Function;
|
|
-import java.util.stream.Collectors;
|
|
-import java.util.stream.Stream;
|
|
-import javax.annotation.Nullable;
|
|
-import javax.imageio.ImageIO;
|
|
-import net.minecraft.CrashReport;
|
|
-import net.minecraft.ReportedException;
|
|
-import net.minecraft.SharedConstants;
|
|
-import net.minecraft.SystemReport;
|
|
-import net.minecraft.Util;
|
|
+import joptsimple.OptionSet;
|
|
+import net.minecraft.*;
|
|
import net.minecraft.commands.CommandSource;
|
|
import net.minecraft.commands.CommandSourceStack;
|
|
import net.minecraft.commands.Commands;
|
|
-import net.minecraft.core.BlockPos;
|
|
-import net.minecraft.core.HolderGetter;
|
|
-import net.minecraft.core.LayeredRegistryAccess;
|
|
-import net.minecraft.core.Registry;
|
|
-import net.minecraft.core.RegistryAccess;
|
|
+import net.minecraft.core.*;
|
|
import net.minecraft.core.registries.Registries;
|
|
import net.minecraft.data.worldgen.features.MiscOverworldFeatures;
|
|
import net.minecraft.gametest.framework.GameTestTicker;
|
|
@@ -77,15 +35,13 @@ import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundSetTimePacket;
|
|
import net.minecraft.network.protocol.status.ServerStatus;
|
|
import net.minecraft.obfuscate.DontObfuscate;
|
|
+import net.minecraft.resources.RegistryOps;
|
|
import net.minecraft.resources.ResourceKey;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
-import net.minecraft.server.level.DemoMode;
|
|
-import net.minecraft.server.level.PlayerRespawnLogic;
|
|
-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.bossevents.CustomBossEvents;
|
|
+import net.minecraft.server.dedicated.DedicatedServer;
|
|
+import net.minecraft.server.dedicated.DedicatedServerProperties;
|
|
+import net.minecraft.server.level.*;
|
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
|
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
|
|
import net.minecraft.server.network.ServerConnectionListener;
|
|
@@ -100,26 +56,15 @@ import net.minecraft.server.players.GameProfileCache;
|
|
import net.minecraft.server.players.PlayerList;
|
|
import net.minecraft.server.players.ServerOpListEntry;
|
|
import net.minecraft.server.players.UserWhiteList;
|
|
-import net.minecraft.util.Crypt;
|
|
-import net.minecraft.util.CryptException;
|
|
-import net.minecraft.util.FrameTimer;
|
|
-import net.minecraft.util.ModCheck;
|
|
-import net.minecraft.util.Mth;
|
|
-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.*;
|
|
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;
|
|
@@ -133,66 +78,53 @@ import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.flag.FeatureFlagSet;
|
|
import net.minecraft.world.flag.FeatureFlags;
|
|
import net.minecraft.world.item.crafting.RecipeManager;
|
|
-import net.minecraft.world.level.ChunkPos;
|
|
-import net.minecraft.world.level.CustomSpawner;
|
|
-import net.minecraft.world.level.DataPackConfig;
|
|
-import net.minecraft.world.level.ForcedChunksSavedData;
|
|
-import net.minecraft.world.level.GameRules;
|
|
-import net.minecraft.world.level.GameType;
|
|
-import net.minecraft.world.level.Level;
|
|
-import net.minecraft.world.level.LevelSettings;
|
|
-import net.minecraft.world.level.WorldDataConfiguration;
|
|
+import net.minecraft.world.level.*;
|
|
import net.minecraft.world.level.biome.BiomeManager;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.border.WorldBorder;
|
|
import net.minecraft.world.level.dimension.LevelStem;
|
|
-import net.minecraft.world.level.levelgen.WorldOptions;
|
|
+import net.minecraft.world.level.levelgen.*;
|
|
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
|
|
+import net.minecraft.world.level.levelgen.presets.WorldPresets;
|
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
|
-import net.minecraft.world.level.storage.CommandStorage;
|
|
-import net.minecraft.world.level.storage.DimensionDataStorage;
|
|
-import net.minecraft.world.level.storage.LevelData;
|
|
-import net.minecraft.world.level.storage.LevelResource;
|
|
-import net.minecraft.world.level.storage.LevelStorageSource;
|
|
-import net.minecraft.world.level.storage.PlayerDataStorage;
|
|
-import net.minecraft.world.level.storage.PrimaryLevelData;
|
|
-import net.minecraft.world.level.storage.ServerLevelData;
|
|
-import net.minecraft.world.level.storage.WorldData;
|
|
+import net.minecraft.world.level.storage.*;
|
|
import net.minecraft.world.level.storage.loot.ItemModifierManager;
|
|
import net.minecraft.world.level.storage.loot.LootTables;
|
|
import net.minecraft.world.level.storage.loot.PredicateManager;
|
|
import net.minecraft.world.phys.Vec2;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.apache.commons.lang3.Validate;
|
|
-import org.slf4j.Logger;
|
|
-
|
|
-// CraftBukkit start
|
|
-import com.mojang.datafixers.util.Pair;
|
|
-import com.mojang.serialization.DynamicOps;
|
|
-import com.mojang.serialization.Lifecycle;
|
|
-import java.util.Random;
|
|
-// import jline.console.ConsoleReader; // Paper
|
|
-import joptsimple.OptionSet;
|
|
-import net.minecraft.core.HolderLookup;
|
|
-import net.minecraft.resources.RegistryOps;
|
|
-import net.minecraft.server.bossevents.CustomBossEvents;
|
|
-import net.minecraft.server.dedicated.DedicatedServer;
|
|
-import net.minecraft.server.dedicated.DedicatedServerProperties;
|
|
-import net.minecraft.world.level.levelgen.Heightmap;
|
|
-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
|
|
+import org.slf4j.Logger;
|
|
|
|
-import co.aikar.timings.MinecraftTimings; // Paper
|
|
+import javax.annotation.Nullable;
|
|
+import javax.imageio.ImageIO;
|
|
+import java.awt.image.BufferedImage;
|
|
+import java.io.BufferedWriter;
|
|
+import java.io.ByteArrayOutputStream;
|
|
+import java.io.File;
|
|
+import java.io.IOException;
|
|
+import java.lang.management.ManagementFactory;
|
|
+import java.lang.management.ThreadInfo;
|
|
+import java.lang.management.ThreadMXBean;
|
|
+import java.net.Proxy;
|
|
+import java.nio.charset.StandardCharsets;
|
|
+import java.nio.file.Files;
|
|
+import java.nio.file.Path;
|
|
+import java.security.KeyPair;
|
|
+import java.util.*;
|
|
+import java.util.Map.Entry;
|
|
+import java.util.concurrent.CompletableFuture;
|
|
+import java.util.concurrent.Executor;
|
|
+import java.util.concurrent.ForkJoinPool;
|
|
+import java.util.concurrent.RejectedExecutionException;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+import java.util.concurrent.atomic.AtomicReference;
|
|
+import java.util.function.BooleanSupplier;
|
|
+import java.util.function.Consumer;
|
|
+import java.util.function.Function;
|
|
+import java.util.stream.Collectors;
|
|
+import java.util.stream.Stream;
|
|
|
|
public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements CommandSource, AutoCloseable {
|
|
|
|
@@ -284,6 +216,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
protected WorldData worldData;
|
|
private volatile boolean isSaving;
|
|
|
|
+ public boolean asyncEntityEnabled;
|
|
+ private final boolean asyncExecutorEnabled;
|
|
+ private int asyncExecutorThreadCount;
|
|
+ private final AtomicInteger threadId = new AtomicInteger();
|
|
+ public ForkJoinPool asyncExecutor;
|
|
+
|
|
// CraftBukkit start
|
|
public final WorldLoader.DataLoadContext worldLoader;
|
|
public org.bukkit.craftbukkit.CraftServer server;
|
|
@@ -410,6 +348,21 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
// Paper end
|
|
Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
|
|
this.paperConfigurations = services.paperConfigurations(); // Paper
|
|
+ //Hearse start
|
|
+ HearseConfig.init();
|
|
+ this.asyncEntityEnabled = HearseConfig.getBoolean("enable-async-entity",true);
|
|
+ this.asyncExecutorThreadCount = HearseConfig.getInt("async-entity-executor-thread-count",Runtime.getRuntime().availableProcessors());
|
|
+ this.asyncExecutorEnabled = this.asyncEntityEnabled;
|
|
+ if (this.asyncExecutorEnabled){
|
|
+ this.asyncExecutor = new ForkJoinPool(this.asyncExecutorThreadCount,forkJoinPool -> {
|
|
+ ForkJoinTickThread worker = new ForkJoinTickThread(forkJoinPool);
|
|
+ worker.setDaemon(true);
|
|
+ worker.setContextClassLoader(MinecraftServer.class.getClassLoader());
|
|
+ worker.setName("Hearse-ForkJoin-Worker # "+this.threadId.getAndIncrement());
|
|
+ return worker;
|
|
+ },null,true);
|
|
+ }
|
|
+ //Hearse end
|
|
}
|
|
// CraftBukkit end
|
|
|
|
@@ -915,6 +868,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
// CraftBukkit end
|
|
|
|
public void stopServer() {
|
|
+ HearseConfig.save();//Hearse
|
|
// CraftBukkit start - prevent double stopping on multiple threads
|
|
synchronized(this.stopLock) {
|
|
if (this.hasStopped) return;
|
|
@@ -1333,17 +1287,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
|
|
}
|
|
}
|
|
@@ -1522,11 +1471,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
|
|
@@ -1557,7 +1504,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/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
index bc46479fd0622a90fd98ac88f92b2840a22a2d04..ad000a2bb5b0bc0e231af566777b51c70c91002d 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
|
@@ -2,6 +2,7 @@ package net.minecraft.server.level;
|
|
|
|
import com.mojang.datafixers.util.Either;
|
|
import com.mojang.datafixers.util.Pair;
|
|
+import it.unimi.dsi.fastutil.shorts.ShortArraySet;
|
|
import it.unimi.dsi.fastutil.shorts.ShortOpenHashSet;
|
|
import it.unimi.dsi.fastutil.shorts.ShortSet;
|
|
import java.util.ArrayList;
|
|
@@ -14,6 +15,9 @@ import java.util.concurrent.atomic.AtomicReferenceArray;
|
|
import java.util.function.IntConsumer;
|
|
import java.util.function.IntSupplier;
|
|
import javax.annotation.Nullable;
|
|
+
|
|
+import it.unimi.dsi.fastutil.shorts.ShortSets;
|
|
+import net.himeki.mcmtfabric.parallelised.fastutil.ConcurrentShortHashSet;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.SectionPos;
|
|
@@ -233,7 +237,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] = new ShortOpenHashSet();
|
|
+ this.changedBlocksPerSection[i] = new ConcurrentShortHashSet();
|
|
}
|
|
|
|
this.changedBlocksPerSection[i].add(SectionPos.sectionRelativePos(pos));
|
|
@@ -302,8 +306,7 @@ public class ChunkHolder {
|
|
|
|
for (j = 0; j < this.changedBlocksPerSection.length; ++j) {
|
|
ShortSet shortset = this.changedBlocksPerSection[j];
|
|
-
|
|
- if (shortset != null) {
|
|
+ if (shortset!=null){
|
|
int k = this.levelHeightAccessor.getSectionYFromSectionIndex(j);
|
|
SectionPos sectionposition = SectionPos.of(chunk.getPos(), k);
|
|
|
|
@@ -315,14 +318,13 @@ public class ChunkHolder {
|
|
this.broadcastBlockEntityIfNeeded(world, blockposition, iblockdata);
|
|
} else {
|
|
LevelChunkSection chunksection = chunk.getSection(j);
|
|
- ClientboundSectionBlocksUpdatePacket packetplayoutmultiblockchange = new ClientboundSectionBlocksUpdatePacket(sectionposition, shortset, chunksection, this.resendLight);
|
|
+ ClientboundSectionBlocksUpdatePacket packetplayoutmultiblockchange = new ClientboundSectionBlocksUpdatePacket(sectionposition,shortset, chunksection, this.resendLight);
|
|
|
|
this.broadcast(packetplayoutmultiblockchange, false);
|
|
packetplayoutmultiblockchange.runUpdates((blockposition1, iblockdata1) -> {
|
|
this.broadcastBlockEntityIfNeeded(world, blockposition1, iblockdata1);
|
|
});
|
|
}
|
|
-
|
|
this.changedBlocksPerSection[j] = null;
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index beb7c22cb63021f26c06f91050361e1b25fcc72d..1248549d17a8c07579f413c2143bba029868d0e9 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -1,57 +1,21 @@
|
|
package net.minecraft.server.level;
|
|
|
|
-import co.aikar.timings.Timing; // Paper
|
|
-import com.google.common.collect.ImmutableList;
|
|
+import com.google.common.collect.*;
|
|
import com.google.common.collect.ImmutableList.Builder;
|
|
-import com.google.common.collect.Iterables;
|
|
-import com.google.common.collect.ComparisonChain; // Paper
|
|
-import com.google.common.collect.Lists;
|
|
-import com.google.common.collect.Queues;
|
|
-import com.google.common.collect.Sets;
|
|
import com.google.gson.JsonElement;
|
|
import com.mojang.datafixers.DataFixer;
|
|
import com.mojang.datafixers.util.Either;
|
|
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.Int2ObjectOpenHashMap;
|
|
+import io.papermc.paper.util.MCUtil;
|
|
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
|
|
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
|
|
import it.unimi.dsi.fastutil.longs.Long2LongMap;
|
|
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
|
|
-import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
|
-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 java.io.IOException;
|
|
-import java.io.Writer;
|
|
-import java.nio.file.Path;
|
|
-import java.util.ArrayList;
|
|
-import java.util.BitSet;
|
|
-import java.util.Iterator;
|
|
-import java.util.List;
|
|
-import java.util.Locale;
|
|
-import java.util.Objects;
|
|
-import java.util.Optional;
|
|
-import java.util.Queue;
|
|
-import java.util.Set;
|
|
-import java.util.concurrent.CancellationException;
|
|
-import java.util.concurrent.CompletableFuture;
|
|
-import java.util.concurrent.CompletionException;
|
|
-import java.util.concurrent.CompletionStage;
|
|
-import java.util.concurrent.Executor;
|
|
-import java.util.concurrent.atomic.AtomicInteger;
|
|
-import java.util.function.BooleanSupplier;
|
|
-import java.util.function.Consumer;
|
|
-import java.util.function.IntFunction;
|
|
-import java.util.function.IntSupplier;
|
|
-import java.util.function.Supplier;
|
|
-import java.util.stream.Collectors;
|
|
-import javax.annotation.Nullable;
|
|
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
|
+import it.unimi.dsi.fastutil.objects.ReferenceSet;
|
|
+import it.unimi.dsi.fastutil.objects.ReferenceSets;
|
|
import net.minecraft.CrashReport;
|
|
import net.minecraft.CrashReportCategory;
|
|
import net.minecraft.ReportedException;
|
|
@@ -63,36 +27,19 @@ import net.minecraft.core.registries.Registries;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.network.protocol.Packet;
|
|
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
|
-import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket;
|
|
-import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket;
|
|
-import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
|
|
import net.minecraft.network.protocol.game.DebugPackets;
|
|
-import io.papermc.paper.util.MCUtil;
|
|
import net.minecraft.server.MinecraftServer;
|
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
|
import net.minecraft.server.network.ServerPlayerConnection;
|
|
-import net.minecraft.util.CsvOutput;
|
|
import net.minecraft.util.Mth;
|
|
-import net.minecraft.util.profiling.ProfilerFiller;
|
|
import net.minecraft.util.thread.BlockableEventLoop;
|
|
-import net.minecraft.util.thread.ProcessorHandle;
|
|
-import net.minecraft.util.thread.ProcessorMailbox;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntityType;
|
|
-import net.minecraft.world.entity.Mob;
|
|
import net.minecraft.world.entity.ai.village.poi.PoiManager;
|
|
import net.minecraft.world.entity.boss.EnderDragonPart;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
import net.minecraft.world.level.GameRules;
|
|
-import net.minecraft.world.level.chunk.ChunkAccess;
|
|
-import net.minecraft.world.level.chunk.ChunkGenerator;
|
|
-import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
|
-import net.minecraft.world.level.chunk.ChunkStatus;
|
|
-import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
|
-import net.minecraft.world.level.chunk.LevelChunk;
|
|
-import net.minecraft.world.level.chunk.LightChunkGetter;
|
|
-import net.minecraft.world.level.chunk.ProtoChunk;
|
|
-import net.minecraft.world.level.chunk.UpgradeData;
|
|
+import net.minecraft.world.level.chunk.*;
|
|
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
|
import net.minecraft.world.level.chunk.storage.ChunkStorage;
|
|
import net.minecraft.world.level.entity.ChunkStatusUpdateListener;
|
|
@@ -101,19 +48,26 @@ import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
|
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
|
|
import net.minecraft.world.level.levelgen.RandomState;
|
|
import net.minecraft.world.level.levelgen.blending.BlendingData;
|
|
-import net.minecraft.world.level.levelgen.structure.StructureStart;
|
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
|
import net.minecraft.world.level.storage.DimensionDataStorage;
|
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
|
-import net.minecraft.world.phys.Vec3;
|
|
-import org.apache.commons.lang3.mutable.MutableBoolean;
|
|
import org.apache.commons.lang3.mutable.MutableObject;
|
|
-import org.slf4j.Logger;
|
|
import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
|
|
-import org.bukkit.entity.Player;
|
|
+import org.slf4j.Logger;
|
|
+
|
|
+import javax.annotation.Nullable;
|
|
+import java.io.IOException;
|
|
+import java.io.Writer;
|
|
+import java.nio.file.Path;
|
|
+import java.util.*;
|
|
+import java.util.concurrent.CancellationException;
|
|
+import java.util.concurrent.CompletableFuture;
|
|
+import java.util.concurrent.CompletionException;
|
|
+import java.util.concurrent.Executor;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+import java.util.function.*;
|
|
// CraftBukkit end
|
|
|
|
-import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
|
|
|
|
public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider {
|
|
|
|
@@ -147,13 +101,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
public final StructureTemplateManager structureTemplateManager; // Paper - rewrite chunk system
|
|
private final String storageName;
|
|
private final PlayerMap playerMap;
|
|
- public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap;
|
|
+ public final Map<Integer, TrackedEntity> entityMap;
|
|
private final Long2ByteMap chunkTypeCache;
|
|
private final Long2LongMap chunkSaveCooldowns;
|
|
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 +249,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 = Maps.newConcurrentMap();
|
|
this.chunkTypeCache = new Long2ByteOpenHashMap();
|
|
this.chunkSaveCooldowns = new Long2LongOpenHashMap();
|
|
this.unloadQueue = Queues.newConcurrentLinkedQueue();
|
|
@@ -1209,11 +1163,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
ServerPlayer entityplayer = (ServerPlayer) entity;
|
|
|
|
this.updatePlayerStatus(entityplayer, true);
|
|
- ObjectIterator objectiterator = this.entityMap.values().iterator();
|
|
-
|
|
- while (objectiterator.hasNext()) {
|
|
- ChunkMap.TrackedEntity playerchunkmap_entitytracker1 = (ChunkMap.TrackedEntity) objectiterator.next();
|
|
-
|
|
+ for (TrackedEntity playerchunkmap_entitytracker1 : this.entityMap.values()) {
|
|
if (playerchunkmap_entitytracker1.entity != entityplayer) {
|
|
playerchunkmap_entitytracker1.updatePlayer(entityplayer);
|
|
}
|
|
@@ -1231,11 +1181,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
ServerPlayer entityplayer = (ServerPlayer) entity;
|
|
|
|
this.updatePlayerStatus(entityplayer, false);
|
|
- ObjectIterator objectiterator = this.entityMap.values().iterator();
|
|
-
|
|
- while (objectiterator.hasNext()) {
|
|
- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
|
|
|
|
+ for (TrackedEntity playerchunkmap_entitytracker : this.entityMap.values()) {
|
|
playerchunkmap_entitytracker.removePlayer(entityplayer);
|
|
}
|
|
}
|
|
@@ -1281,7 +1228,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
// Paper end - optimized tracker
|
|
List<ServerPlayer> list = Lists.newArrayList();
|
|
List<ServerPlayer> list1 = this.level.players();
|
|
- ObjectIterator objectiterator = this.entityMap.values().iterator();
|
|
+ Iterator objectiterator = this.entityMap.values().iterator();
|
|
//level.timings.tracker1.startTiming(); // Paper // Purpur
|
|
|
|
ChunkMap.TrackedEntity playerchunkmap_entitytracker;
|
|
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
|
index 52cba8f68d274cce106304aef1249a95474d3238..3dd4d3b0ec9732df363966d124bbf6da96d9f047 100644
|
|
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
|
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
|
@@ -30,6 +30,8 @@ import java.util.Set;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.Executor;
|
|
import javax.annotation.Nullable;
|
|
+
|
|
+import net.himeki.mcmtfabric.parallelised.fastutil.Long2ObjectOpenConcurrentHashMap;
|
|
import net.minecraft.core.SectionPos;
|
|
import net.minecraft.util.SortedArraySet;
|
|
import net.minecraft.util.thread.ProcessorHandle;
|
|
@@ -52,7 +54,7 @@ public abstract class DistanceManager {
|
|
private static final int INITIAL_TICKET_LIST_CAPACITY = 4;
|
|
private static final int ENTITY_TICKING_LEVEL_THRESHOLD = 32;
|
|
private static final int BLOCK_TICKING_LEVEL_THRESHOLD = 33;
|
|
- final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap();
|
|
+ final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenConcurrentHashMap<>();
|
|
// Paper - rewrite chunk system
|
|
public static final int MOB_SPAWN_RANGE = 8; // private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8); // Paper - no longer used
|
|
//private final TickingTracker tickingTicketsTracker = new TickingTracker(); // Paper - no longer used
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
index 0ae45cf5a084fd412305e8b2f5dabe608b4eb1c1..4ac0a4eb95ab34a3409b66ee8d96af0846c6ec8c 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"); // Purpur
|
|
//this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing // Purpur
|
|
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
|
|
@@ -848,12 +843,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/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
index 50cf4d200bc2892f2140c9929193b4b20ad2bd17..51a65ced1619d549fb6b0c4e7305839e8db2c3e5 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
@@ -102,7 +102,7 @@ public class ServerEntity {
|
|
if (entity instanceof ItemFrame) {
|
|
ItemFrame entityitemframe = (ItemFrame) entity;
|
|
|
|
- if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block
|
|
+ if (true) { // CraftBukkit - Moved below, should always enter this block
|
|
ItemStack itemstack = entityitemframe.getItem();
|
|
|
|
if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
index 03b8ef3409fd5f7a4d4b06e13cf8eb22b3bbf8a1..59fc7c0d4c99324c57fcb2edf41c4414f689e931 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -1,69 +1,33 @@
|
|
package net.minecraft.server.level;
|
|
|
|
+import co.aikar.timings.TimingHistory;
|
|
+import co.m2ek4u.hearse.ForkJoinTickThread;
|
|
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.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.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.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;
|
|
@@ -71,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;
|
|
@@ -102,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;
|
|
@@ -128,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;
|
|
@@ -158,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 {
|
|
|
|
@@ -204,7 +156,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;
|
|
@@ -269,10 +221,8 @@ 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) {
|
|
- this.getChunkSource().mainThreadProcessor.execute(() -> {
|
|
- this.loadChunksForMoveAsync(axisalignedbb, priority, onLoad);
|
|
- });
|
|
+ if (Thread.currentThread() != this.thread && !ForkJoinTickThread.isAnotherForKJoinTickThread()) {
|
|
+ this.getChunkSource().mainThreadProcessor.execute(() -> this.loadChunksForMoveAsync(axisalignedbb, priority, onLoad));
|
|
return;
|
|
}
|
|
List<net.minecraft.world.level.chunk.ChunkAccess> ret = new java.util.ArrayList<>();
|
|
@@ -322,7 +272,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
for (int cx = minChunkX; cx <= maxChunkX; ++cx) {
|
|
for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) {
|
|
io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(
|
|
- this, cx, cz, net.minecraft.world.level.chunk.ChunkStatus.FULL, true, priority, consumer
|
|
+ this, cx, cz, net.minecraft.world.level.chunk.ChunkStatus.FULL, true, priority, consumer
|
|
);
|
|
}
|
|
}
|
|
@@ -331,7 +281,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
// Paper start - rewrite chunk system
|
|
public final io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler chunkTaskScheduler;
|
|
public final io.papermc.paper.chunk.system.io.RegionFileIOThread.ChunkDataController chunkDataControllerNew
|
|
- = new io.papermc.paper.chunk.system.io.RegionFileIOThread.ChunkDataController(io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.CHUNK_DATA) {
|
|
+ = new io.papermc.paper.chunk.system.io.RegionFileIOThread.ChunkDataController(io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.CHUNK_DATA) {
|
|
|
|
@Override
|
|
public net.minecraft.world.level.chunk.storage.RegionFileStorage getCache() {
|
|
@@ -349,7 +299,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
}
|
|
};
|
|
public final io.papermc.paper.chunk.system.io.RegionFileIOThread.ChunkDataController poiDataControllerNew
|
|
- = new io.papermc.paper.chunk.system.io.RegionFileIOThread.ChunkDataController(io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.POI_DATA) {
|
|
+ = new io.papermc.paper.chunk.system.io.RegionFileIOThread.ChunkDataController(io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.POI_DATA) {
|
|
|
|
@Override
|
|
public net.minecraft.world.level.chunk.storage.RegionFileStorage getCache() {
|
|
@@ -367,7 +317,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
}
|
|
};
|
|
public final io.papermc.paper.chunk.system.io.RegionFileIOThread.ChunkDataController entityDataControllerNew
|
|
- = new io.papermc.paper.chunk.system.io.RegionFileIOThread.ChunkDataController(io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.ENTITY_DATA) {
|
|
+ = new io.papermc.paper.chunk.system.io.RegionFileIOThread.ChunkDataController(io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.ENTITY_DATA) {
|
|
|
|
@Override
|
|
public net.minecraft.world.level.chunk.storage.RegionFileStorage getCache() {
|
|
@@ -396,8 +346,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
ChunkPos nbtPos = nbt == null ? null : EntityStorage.readChunkPos(nbt);
|
|
if (nbtPos != null && !pos.equals(nbtPos)) {
|
|
throw new IllegalArgumentException(
|
|
- "Entity chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + pos.toString()
|
|
- + " but compound says coordinate is " + nbtPos + " for world: " + this
|
|
+ "Entity chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + pos.toString()
|
|
+ + " but compound says coordinate is " + nbtPos + " for world: " + this
|
|
);
|
|
}
|
|
super.write(pos, nbt);
|
|
@@ -407,8 +357,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
private void writeEntityChunk(int chunkX, int chunkZ, net.minecraft.nbt.CompoundTag compound) throws IOException {
|
|
if (!io.papermc.paper.chunk.system.io.RegionFileIOThread.isRegionFileThread()) {
|
|
io.papermc.paper.chunk.system.io.RegionFileIOThread.scheduleSave(
|
|
- this, chunkX, chunkZ, compound,
|
|
- io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.ENTITY_DATA);
|
|
+ this, chunkX, chunkZ, compound,
|
|
+ io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.ENTITY_DATA);
|
|
return;
|
|
}
|
|
this.entityStorage.write(new ChunkPos(chunkX, chunkZ), compound);
|
|
@@ -417,8 +367,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
private net.minecraft.nbt.CompoundTag readEntityChunk(int chunkX, int chunkZ) throws IOException {
|
|
if (!io.papermc.paper.chunk.system.io.RegionFileIOThread.isRegionFileThread()) {
|
|
return io.papermc.paper.chunk.system.io.RegionFileIOThread.loadData(
|
|
- this, chunkX, chunkZ, io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.ENTITY_DATA,
|
|
- io.papermc.paper.chunk.system.io.RegionFileIOThread.getIOBlockingPriorityForCurrentThread()
|
|
+ this, chunkX, chunkZ, io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.ENTITY_DATA,
|
|
+ io.papermc.paper.chunk.system.io.RegionFileIOThread.getIOBlockingPriorityForCurrentThread()
|
|
);
|
|
}
|
|
return this.entityStorage.read(new ChunkPos(chunkX, chunkZ));
|
|
@@ -536,8 +486,8 @@ 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.navigatingMobs = Sets.newConcurrentHashSet();
|
|
+ this.blockEvents = new ConcurrentLinkedDeque<>();
|
|
this.blockEventsToReschedule = new ArrayList(64);
|
|
this.dragonParts = new Int2ObjectOpenHashMap();
|
|
this.tickTime = flag1;
|
|
@@ -709,41 +659,44 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
org.spigotmc.ActivationRange.activateEntities(this); // Spigot
|
|
//timings.entityTick.startTiming(); // Spigot // Purpur
|
|
this.entityTickList.forEach((entity) -> {
|
|
- entity.activatedPriorityReset = false; // Pufferfish - DAB
|
|
+ entity.activatedPriorityReset = false;
|
|
if (!entity.isRemoved()) {
|
|
- if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed
|
|
+ synchronized (this.entityTickList){
|
|
+ MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick //Hearse -- Move up
|
|
+ }
|
|
+ if (false) { // 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
|
|
+ if (MinecraftServer.getServer().asyncEntityEnabled){
|
|
+ MinecraftServer.getServer().asyncExecutor.execute(()->{
|
|
+ entity.checkDespawn();
|
|
+ Entity entity1 = entity.getVehicle();
|
|
+ if (entity1 != null) {
|
|
+ if (!entity1.isRemoved() && entity1.hasPassenger(entity)) {
|
|
+ return;
|
|
+ }
|
|
+ entity.stopRiding();
|
|
+ }
|
|
+ try {
|
|
+ this.tickNonPassenger(entity); // Pufferfish - changed
|
|
+ } catch (Throwable throwable) {
|
|
+ throwable.printStackTrace();
|
|
+ }
|
|
+ });
|
|
+ }else{
|
|
+ entity.checkDespawn();
|
|
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
|
|
+ try {
|
|
+ this.tickNonPassenger(entity); // Pufferfish - changed
|
|
+ } catch (Throwable throwable) {
|
|
+ throwable.printStackTrace();
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
@@ -993,7 +946,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");
|
|
@@ -1197,9 +1150,9 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
currentlyTickingEntity.lazySet(entity);
|
|
}
|
|
// Paper end - log detailed entity tick information
|
|
- ++TimingHistory.entityTicks; // Paper - timings
|
|
- // Spigot start
|
|
- co.aikar.timings.Timing timer; // Paper
|
|
+ ++TimingHistory.entityTicks; // Paper - timings
|
|
+ // Spigot start
|
|
+ co.aikar.timings.Timing timer; // Paper
|
|
/*if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { // Paper - comment out - EAR 2, reimplement below
|
|
entity.tickCount++;
|
|
timer = entity.getType().inactiveTickTimer.startTiming(); try { // Paper - timings
|
|
@@ -1207,36 +1160,36 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
} finally { timer.stopTiming(); } // Paper
|
|
return;
|
|
}*/ // Paper - comment out EAR 2
|
|
- // Spigot end
|
|
- // Paper start- timings
|
|
- final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity);
|
|
- //timer = isActive ? entity.getType().tickTimer.startTiming() : entity.getType().inactiveTickTimer.startTiming(); // Paper // Purpur
|
|
- //try { // Purpur
|
|
- // Paper end - timings
|
|
- entity.setOldPosAndRot();
|
|
- //ProfilerFiller gameprofilerfiller = this.getProfiler(); // Purpur
|
|
-
|
|
- ++entity.tickCount;
|
|
+ // Spigot end
|
|
+ // Paper start- timings
|
|
+ final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity);
|
|
+ //timer = isActive ? entity.getType().tickTimer.startTiming() : entity.getType().inactiveTickTimer.startTiming(); // Paper // Purpur
|
|
+ //try { // Purpur
|
|
+ // Paper end - timings
|
|
+ entity.setOldPosAndRot();
|
|
+ //ProfilerFiller gameprofilerfiller = this.getProfiler(); // Purpur
|
|
+
|
|
+ ++entity.tickCount;
|
|
/*this.getProfiler().push(() -> { // Purpur
|
|
return BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString();
|
|
});*/ // Purpur
|
|
- //gameprofilerfiller.incrementCounter("tickNonPassenger"); // Purpur
|
|
- if (isActive) { // Paper - EAR 2
|
|
- TimingHistory.activatedEntityTicks++;
|
|
- entity.tick();
|
|
- entity.postTick(); // CraftBukkit
|
|
- } else { entity.inactiveTick(); } // Paper - EAR 2
|
|
- //this.getProfiler().pop(); // Purpur
|
|
- //} finally { timer.stopTiming(); } // Paper - timings // Purpur
|
|
- Iterator iterator = entity.getPassengers().iterator();
|
|
+ //gameprofilerfiller.incrementCounter("tickNonPassenger"); // Purpur
|
|
+ if (isActive) { // Paper - EAR 2
|
|
+ TimingHistory.activatedEntityTicks++;
|
|
+ entity.tick();
|
|
+ entity.postTick(); // CraftBukkit
|
|
+ } 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();
|
|
+ while (iterator.hasNext()) {
|
|
+ Entity entity1 = (Entity) iterator.next();
|
|
|
|
- this.tickPassenger(entity, entity1);
|
|
- }
|
|
- // } finally { timer.stopTiming(); } // Paper - timings - move up
|
|
- // Paper start - log detailed entity tick information
|
|
+ this.tickPassenger(entity, entity1);
|
|
+ }
|
|
+ // } finally { timer.stopTiming(); } // Paper - timings - move up
|
|
+ // Paper start - log detailed entity tick information
|
|
} finally {
|
|
if (currentlyTickingEntity.get() == entity) {
|
|
currentlyTickingEntity.lazySet(null);
|
|
@@ -1263,8 +1216,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
//gameprofilerfiller.incrementCounter("tickPassenger"); // Purpur
|
|
// Paper start - EAR 2
|
|
if (isActive) {
|
|
- passenger.rideTick();
|
|
- passenger.postTick(); // CraftBukkit
|
|
+ passenger.rideTick();
|
|
+ passenger.postTick(); // CraftBukkit
|
|
} else {
|
|
passenger.setDeltaMovement(Vec3.ZERO);
|
|
passenger.inactiveTick();
|
|
@@ -1281,7 +1234,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
this.tickPassenger(passenger, entity2);
|
|
}
|
|
|
|
- //} finally { timer.stopTiming(); }// Paper - EAR2 timings // Purpur
|
|
+ //} finally { timer.stopTiming(); }// Paper - EAR2 timings // Purpur
|
|
}
|
|
} else {
|
|
passenger.stopRiding();
|
|
@@ -1302,24 +1255,24 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
}
|
|
|
|
//try (co.aikar.timings.Timing ignored = this.timings.worldSave.startTiming()) { // Purpur
|
|
- if (doFull) {
|
|
- this.saveLevelData();
|
|
- }
|
|
+ if (doFull) {
|
|
+ this.saveLevelData();
|
|
+ }
|
|
|
|
- //this.timings.worldSaveChunks.startTiming(); // Paper // Purpur
|
|
- if (!this.noSave()) chunkproviderserver.saveIncrementally();
|
|
- //this.timings.worldSaveChunks.stopTiming(); // Paper // Purpur
|
|
+ //this.timings.worldSaveChunks.startTiming(); // Paper // Purpur
|
|
+ if (!this.noSave()) chunkproviderserver.saveIncrementally();
|
|
+ //this.timings.worldSaveChunks.stopTiming(); // Paper // Purpur
|
|
|
|
- // Copied from save()
|
|
- // CraftBukkit start - moved from MinecraftServer.saveChunks
|
|
- if (doFull) { // Paper
|
|
- ServerLevel worldserver1 = this;
|
|
+ // Copied from save()
|
|
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
|
|
+ if (doFull) { // Paper
|
|
+ ServerLevel worldserver1 = this;
|
|
|
|
- this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
|
|
- this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save());
|
|
- this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
|
|
- }
|
|
- // CraftBukkit end
|
|
+ this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
|
|
+ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save());
|
|
+ this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
|
|
+ }
|
|
+ // CraftBukkit end
|
|
//} // Purpur
|
|
}
|
|
// Paper end
|
|
@@ -1344,10 +1297,10 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
progressListener.progressStage(Component.translatable("menu.savingChunks"));
|
|
}
|
|
|
|
- //timings.worldSaveChunks.startTiming(); // Paper // Purpur
|
|
+ //timings.worldSaveChunks.startTiming(); // Paper // Purpur
|
|
if (!close) chunkproviderserver.save(flush); // Paper - rewrite chunk system
|
|
if (close) chunkproviderserver.close(true); // Paper - rewrite chunk system
|
|
- //timings.worldSaveChunks.stopTiming(); // Paper // Purpur
|
|
+ //timings.worldSaveChunks.stopTiming(); // Paper // Purpur
|
|
//}// Paper // Purpur
|
|
// Paper - rewrite chunk system - entity saving moved into ChunkHolder
|
|
|
|
@@ -1662,54 +1615,53 @@ 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";
|
|
-
|
|
- Util.logAndPauseIfInIde("recursive call to sendBlockUpdated", new IllegalStateException("recursive call to sendBlockUpdated"));
|
|
+ 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);
|
|
+ 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();
|
|
+ navigationabstract1.recomputePath();
|
|
+ }
|
|
+ } finally {
|
|
+ this.isUpdatingNavigations = false;
|
|
}
|
|
- } finally {
|
|
- this.isUpdatingNavigations = false;
|
|
- }
|
|
|
|
- }
|
|
+ }
|
|
} // Paper
|
|
}
|
|
|
|
@@ -1777,13 +1729,11 @@ 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 = 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()));
|
|
+ this.server.getPlayerList().broadcast(null, blockactiondata.pos().getX(), blockactiondata.pos().getY(), (double) blockactiondata.pos().getZ(), 64.0D, this.dimension(), new ClientboundBlockEventPacket(blockactiondata.pos(), blockactiondata.block(), blockactiondata.paramA(), blockactiondata.paramB()));
|
|
}
|
|
} else {
|
|
this.blockEventsToReschedule.add(blockactiondata);
|
|
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/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/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
|
index 83701fbfaa56a232593ee8f11a3afb8941238bfa..51f0439f3ad94dce17a2be6197e21d0ca3bedf9f 100644
|
|
--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
|
+++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
|
@@ -3,9 +3,12 @@ package net.minecraft.util.thread;
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.google.common.collect.Queues;
|
|
import com.mojang.logging.LogUtils;
|
|
+
|
|
+import java.util.Deque;
|
|
import java.util.List;
|
|
import java.util.Queue;
|
|
import java.util.concurrent.CompletableFuture;
|
|
+import java.util.concurrent.ConcurrentLinkedDeque;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.concurrent.locks.LockSupport;
|
|
import java.util.function.BooleanSupplier;
|
|
@@ -19,7 +22,7 @@ import org.slf4j.Logger;
|
|
public abstract class BlockableEventLoop<R extends Runnable> implements ProfilerMeasured, ProcessorHandle<R>, Executor {
|
|
private final String name;
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
- private final Queue<R> pendingRunnables = Queues.newConcurrentLinkedQueue();
|
|
+ private final Deque<R> pendingRunnables = new ConcurrentLinkedDeque<>();
|
|
private int blockingCount;
|
|
|
|
protected BlockableEventLoop(String name) {
|
|
@@ -117,13 +120,14 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
|
|
}
|
|
|
|
public boolean pollTask() {
|
|
- R runnable = this.pendingRunnables.peek();
|
|
+ R runnable = this.pendingRunnables.poll();
|
|
if (runnable == null) {
|
|
return false;
|
|
} else if (this.blockingCount == 0 && !this.shouldRun(runnable)) {
|
|
+ this.pendingRunnables.addFirst(runnable);
|
|
return false;
|
|
} else {
|
|
- this.doRunTask(this.pendingRunnables.remove());
|
|
+ this.doRunTask(runnable);
|
|
return true;
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
index 75e374b262e2797b593e5f170014a6e0cd95e41e..c4b99be104c323dff9c770e2500fa14075fed06c 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
@@ -484,7 +484,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
|
public int sectionY = Integer.MIN_VALUE;
|
|
public int sectionZ = Integer.MIN_VALUE;
|
|
|
|
- public boolean updatingSectionStatus = false;
|
|
+ public volatile boolean updatingSectionStatus = false;
|
|
// Paper end
|
|
// Paper start - optimise entity tracking
|
|
final org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = org.spigotmc.TrackingRange.getTrackingRangeType(this);
|
|
@@ -4441,12 +4441,6 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
|
}
|
|
// Paper end - block invalid positions
|
|
// Paper end
|
|
- // Paper start - rewrite chunk system
|
|
- if (this.updatingSectionStatus) {
|
|
- LOGGER.error("Refusing to update position for entity " + this + " to position " + new Vec3(x, y, z) + " since it is processing a section status update", new Throwable());
|
|
- return;
|
|
- }
|
|
- // Paper end - rewrite chunk system
|
|
// Paper start - fix MC-4
|
|
if (this instanceof ItemEntity) {
|
|
if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.fixEntityPositionDesync) {
|
|
@@ -4562,10 +4556,6 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
|
public final void setRemoved(Entity.RemovalReason reason) {
|
|
// Paper start - rewrite chunk system
|
|
io.papermc.paper.util.TickThread.ensureTickThread(this, "Cannot remove entity off-main");
|
|
- if (this.updatingSectionStatus) {
|
|
- LOGGER.warn("Entity " + this + " is currently prevented from being added/removed to world since it is processing section status updates", new Throwable());
|
|
- return;
|
|
- }
|
|
// Paper end - rewrite chunk system
|
|
if (this.removalReason == null) {
|
|
this.removalReason = reason;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
|
index 93c32dd39693b37efaa05af0486e1bdd298661f3..6892bd3925890a024679207c0aa7cab12dbdb82d 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;
|
|
@@ -1963,15 +1964,18 @@ public abstract class LivingEntity extends Entity {
|
|
BlockPos blockposition = this.blockPosition();
|
|
BlockState iblockdata = this.getFeetBlockState();
|
|
|
|
- if (iblockdata.is(BlockTags.CLIMBABLE)) {
|
|
- this.lastClimbablePos = Optional.of(blockposition);
|
|
- return true;
|
|
- } else if (iblockdata.getBlock() instanceof TrapDoorBlock && this.trapdoorUsableAsLadder(blockposition, iblockdata)) {
|
|
- this.lastClimbablePos = Optional.of(blockposition);
|
|
- return true;
|
|
- } else {
|
|
- return false;
|
|
+ if (iblockdata!=null){
|
|
+ if (iblockdata.is(BlockTags.CLIMBABLE)) {
|
|
+ this.lastClimbablePos = Optional.of(blockposition);
|
|
+ return true;
|
|
+ } else if (iblockdata.getBlock() instanceof TrapDoorBlock && this.trapdoorUsableAsLadder(blockposition, iblockdata)) {
|
|
+ this.lastClimbablePos = Optional.of(blockposition);
|
|
+ return true;
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
}
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
@@ -3405,9 +3409,11 @@ public abstract class LivingEntity extends Entity {
|
|
this.jumpInLiquid(FluidTags.LAVA);
|
|
} else if ((this.onGround || flag && d7 <= d8) && this.noJumpDelay == 0) {
|
|
if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper
|
|
- this.jumpFromGround();
|
|
- this.noJumpDelay = 10;
|
|
- } else { this.setJumping(false); } // Paper - setJumping(false) stops a potential loop
|
|
+ this.jumpFromGround();
|
|
+ this.noJumpDelay = 10;
|
|
+ } else {
|
|
+ this.setJumping(false);
|
|
+ } // Paper - setJumping(false) stops a potential loop
|
|
}
|
|
} else {
|
|
this.noJumpDelay = 0;
|
|
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
|
index 29fa9ad2223de668c15a5e5b433704b2c4765610..9899a19d351f01f96a28f916894db6189d4c8133 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;
|
|
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..8e1d6032a1edea8d3128fd7e2e3d8fde691eca7e 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
|
|
@@ -35,12 +35,12 @@ public class LongJumpToRandomPos<E extends Mob> extends Behavior<E> {
|
|
private static final int PREPARE_JUMP_DURATION = 40;
|
|
protected static final int MIN_PATHFIND_DISTANCE_TO_VALID_JUMP = 8;
|
|
private static final int TIME_OUT_DURATION = 200;
|
|
- private static final List<Integer> ALLOWED_ANGLES = Lists.newArrayList(65, 70, 75, 80);
|
|
+ private static final List<Integer> ALLOWED_ANGLES = Collections.synchronizedList(Lists.newArrayList(65, 70, 75, 80));
|
|
private final UniformInt timeBetweenLongJumps;
|
|
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/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/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/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
|
index c58496c84b2b3f86890050813041fa49711f3a01..08775845760583e9f7153b99cb94f8e725171a1c 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,7 @@ import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.UUID;
|
|
+import java.util.concurrent.locks.ReentrantLock;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.entity.Entity;
|
|
@@ -239,21 +240,25 @@ 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 ReentrantLock mergeLock = new ReentrantLock(); //MCMT -- fix some concurrent problems
|
|
+
|
|
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
|
|
+ //Hearse -- Just softly lock it,See the pr on MCMT : https://github.com/himekifee/MCMTFabric/pull/42/commits/16749534d808dab5bab434b293337a3cd558a4cf
|
|
+ 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();
|
|
}
|
|
}
|
|
|
|
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 2d222e383d48a1a32eebdb722d770b4fc6c0aca7..2db5342ec8e1c22ee890cc2b4f34a8cea32a3e1e 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
|
@@ -281,9 +281,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
|
this.mobTick(true);
|
|
}
|
|
}
|
|
- maybeDecayGossip();
|
|
+ this.maybeDecayGossip();
|
|
// Paper end
|
|
-
|
|
super.inactiveTick();
|
|
}
|
|
// Spigot End
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
index 2e922bb844bc147224a60ef2aae33a0125e6ca4a..213556c4df3453774fcae29b50803bfd609c1852 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
@@ -16,6 +16,8 @@ import java.util.function.Supplier;
|
|
import java.util.stream.Stream;
|
|
import java.util.stream.StreamSupport;
|
|
import javax.annotation.Nullable;
|
|
+
|
|
+import net.himeki.mcmtfabric.parallelised.fastutil.Int2ObjectConcurrentHashMap;
|
|
import net.minecraft.CrashReport;
|
|
import net.minecraft.CrashReportCategory;
|
|
import net.minecraft.ReportedException;
|
|
@@ -114,10 +116,10 @@ public class LevelChunk extends ChunkAccess {
|
|
this.setBlockNibbles(ca.spottedleaf.starlight.common.light.StarLightEngine.getFilledEmptyLight(world));
|
|
this.setSkyNibbles(ca.spottedleaf.starlight.common.light.StarLightEngine.getFilledEmptyLight(world));
|
|
// Paper end - rewrite light engine
|
|
- this.tickersInLevel = Maps.newHashMap();
|
|
+ this.tickersInLevel = Maps.newConcurrentMap();
|
|
this.clientLightReady = false;
|
|
this.level = (ServerLevel) world; // CraftBukkit - type
|
|
- this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap();
|
|
+ this.gameEventListenerRegistrySections = new Int2ObjectConcurrentHashMap<>();
|
|
Heightmap.Types[] aheightmap_type = Heightmap.Types.values();
|
|
int j = aheightmap_type.length;
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
|
index d783072bc964e45c308197e6f79874eb4a09f871..e63b13484abb7a4f9995f7b8725277caa3edc146 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
|
@@ -21,6 +21,9 @@ import java.util.concurrent.CompletionException;
|
|
import java.util.function.BooleanSupplier;
|
|
import java.util.function.Function;
|
|
import javax.annotation.Nullable;
|
|
+
|
|
+import net.himeki.mcmtfabric.parallelised.fastutil.ConcurrentLongLinkedOpenHashSet;
|
|
+import net.himeki.mcmtfabric.parallelised.fastutil.Long2ObjectOpenConcurrentHashMap;
|
|
import net.minecraft.SharedConstants;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.core.RegistryAccess;
|
|
@@ -38,8 +41,8 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private static final String SECTIONS_TAG = "Sections";
|
|
// Paper - remove mojang I/O thread
|
|
- private final Long2ObjectMap<Optional<R>> storage = new Long2ObjectOpenHashMap<>();
|
|
- private final LongLinkedOpenHashSet dirty = new LongLinkedOpenHashSet();
|
|
+ private final Long2ObjectMap<Optional<R>> storage = new Long2ObjectOpenConcurrentHashMap<>();
|
|
+ private final LongLinkedOpenHashSet dirty = new ConcurrentLongLinkedOpenHashSet();
|
|
private final Function<Runnable, Codec<R>> codec;
|
|
private final Function<Runnable, R> factory;
|
|
private final DataFixer fixerUpper;
|
|
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/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
|
index 57fcf3910f45ce371ac2e237b277b1034caaac4e..c6ad5f54ef0609c8cc2a13844576c5540efb17f3 100644
|
|
--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
|
+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
|
@@ -1,29 +1,38 @@
|
|
package net.minecraft.world.level.entity;
|
|
|
|
-import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
|
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
-import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
|
-import java.util.function.Consumer;
|
|
-import javax.annotation.Nullable;
|
|
+import co.m2ek4u.hearse.ForkJoinTickThread;
|
|
+import co.m2ek4u.hearse.HearseConfig;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectArraySet;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSets;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
import net.minecraft.world.entity.Entity;
|
|
|
|
-public class EntityTickList {
|
|
- public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Entity> entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? // Pufferfish - private->public
|
|
-
|
|
- private void ensureActiveIsNotIterated() {
|
|
- // Paper - replace with better logic, do not delay removals
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.Set;
|
|
+import java.util.concurrent.ForkJoinPool;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+import java.util.function.Consumer;
|
|
|
|
- }
|
|
+public class EntityTickList {
|
|
+ public final Set<Entity> entities = ObjectSets.synchronize(new ObjectArraySet<>());
|
|
+ private static final AtomicInteger threadId = new AtomicInteger();
|
|
+ private static final int threadCount = HearseConfig.getInt("entity-list-foreacher-threadcount",Math.min(Runtime.getRuntime().availableProcessors()/4,2));
|
|
+ private static final ForkJoinPool FOREACH_POOL = new ForkJoinPool(threadCount,forkJoinPool -> {
|
|
+ ForkJoinTickThread worker = new ForkJoinTickThread(forkJoinPool);
|
|
+ worker.setDaemon(true);
|
|
+ worker.setContextClassLoader(MinecraftServer.class.getClassLoader());
|
|
+ worker.setName("Hearse-ForkJoin-Worker # "+threadId.getAndIncrement());
|
|
+ return worker;
|
|
+ },null,true);
|
|
|
|
public void add(Entity entity) {
|
|
io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist addition"); // Paper
|
|
- this.ensureActiveIsNotIterated();
|
|
this.entities.add(entity); // Paper - replace with better logic, do not delay removals/additions
|
|
}
|
|
|
|
public void remove(Entity entity) {
|
|
io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist removal"); // Paper
|
|
- this.ensureActiveIsNotIterated();
|
|
this.entities.remove(entity); // Paper - replace with better logic, do not delay removals/additions
|
|
}
|
|
|
|
@@ -33,17 +42,12 @@ public class EntityTickList {
|
|
|
|
public void forEach(Consumer<Entity> action) {
|
|
io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist iteration"); // Paper
|
|
- // Paper start - replace with better logic, do not delay removals/additions
|
|
- // To ensure nothing weird happens with dimension travelling, do not iterate over new entries...
|
|
- // (by dfl iterator() is configured to not iterate over new entries)
|
|
- io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator<Entity> iterator = this.entities.iterator();
|
|
- try {
|
|
- while (iterator.hasNext()) {
|
|
- action.accept(iterator.next());
|
|
- }
|
|
- } finally {
|
|
- iterator.finishedIterating();
|
|
+
|
|
+ if (MinecraftServer.getServer().asyncEntityEnabled){
|
|
+ final List<Entity> copiedList = new ArrayList<>(this.entities);
|
|
+ FOREACH_POOL.submit(()->copiedList.parallelStream().forEach(action)).join();
|
|
+ }else{
|
|
+ this.entities.forEach(action);
|
|
}
|
|
- // Paper end - replace with better logic, do not delay removals/additions
|
|
}
|
|
}
|
|
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/gameevent/EuclideanGameEventListenerRegistry.java b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
|
|
index 878a42695ecedf0c3f2e6310e3ce44c6b6c36858..b0efa8304dedbc8e2aaa21889278191d9c57b81d 100644
|
|
--- a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
|
|
+++ b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
|
|
@@ -6,14 +6,16 @@ import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
+
|
|
+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 = Lists.newArrayList();
|
|
- private final Set<GameEventListener> listenersToRemove = Sets.newHashSet();
|
|
- private final List<GameEventListener> listenersToAdd = 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;
|
|
private final ServerLevel level;
|
|
|
|
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();
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java b/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java
|
|
index 3d5ce92c77bc107e2ec2f54dc849b99c3abf9718..3c94993f713bb16f17b760b827b797cac29bdace 100644
|
|
--- a/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java
|
|
+++ b/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java
|
|
@@ -6,6 +6,9 @@ import it.unimi.dsi.fastutil.longs.LongArrayList;
|
|
import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
|
|
import it.unimi.dsi.fastutil.longs.LongList;
|
|
import java.util.function.LongPredicate;
|
|
+
|
|
+import net.himeki.mcmtfabric.parallelised.fastutil.ConcurrentLongLinkedOpenHashSet;
|
|
+import net.himeki.mcmtfabric.parallelised.fastutil.Long2ByteConcurrentHashMap;
|
|
import net.minecraft.util.Mth;
|
|
|
|
public abstract class DynamicGraphMinFixedPoint {
|
|
@@ -24,7 +27,7 @@ public abstract class DynamicGraphMinFixedPoint {
|
|
this.queues = new LongLinkedOpenHashSet[levelCount];
|
|
|
|
for(int i = 0; i < levelCount; ++i) {
|
|
- this.queues[i] = new LongLinkedOpenHashSet(expectedLevelSize, 0.5F) {
|
|
+ this.queues[i] = new ConcurrentLongLinkedOpenHashSet(expectedLevelSize, 0.5F) {
|
|
protected void rehash(int i) {
|
|
if (i > expectedLevelSize) {
|
|
super.rehash(i);
|
|
@@ -34,14 +37,7 @@ public abstract class DynamicGraphMinFixedPoint {
|
|
};
|
|
}
|
|
|
|
- this.computedLevels = new Long2ByteOpenHashMap(expectedTotalSize, 0.5F) {
|
|
- protected void rehash(int i) {
|
|
- if (i > expectedTotalSize) {
|
|
- super.rehash(i);
|
|
- }
|
|
-
|
|
- }
|
|
- };
|
|
+ this.computedLevels = new Long2ByteConcurrentHashMap(expectedTotalSize, 0.5F);
|
|
this.computedLevels.defaultReturnValue((byte)-1);
|
|
this.firstQueuedLevel = levelCount;
|
|
}
|
|
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..5db8b0b5a5b43f722a2cf672dfca852d18f78505 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,11 +64,16 @@ public class BinaryHeap {
|
|
|
|
}
|
|
|
|
- public int size() {
|
|
+ public synchronized int size() {
|
|
return this.size;
|
|
}
|
|
|
|
private void upHeap(int index) {
|
|
+ //MCMT -- Fix array out of bounds exception
|
|
+ if (index == -1){
|
|
+ return;
|
|
+ }
|
|
+
|
|
Node node = this.heap[index];
|
|
|
|
int i;
|
|
@@ -90,6 +93,11 @@ public class BinaryHeap {
|
|
}
|
|
|
|
private void downHeap(int index) {
|
|
+ //MCMT -- Fix array out of bounds exception
|
|
+ if (index == -1){
|
|
+ return;
|
|
+ }
|
|
+
|
|
Node node = this.heap[index];
|
|
float f = node.f;
|
|
|
|
@@ -135,11 +143,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..890f510d34fe81b2afbc8b66e974fd427ac6145a 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
|
|
@@ -1,8 +1,10 @@
|
|
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.server.MinecraftServer;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.Mob;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
@@ -11,7 +13,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;
|
|
@@ -39,9 +41,7 @@ public abstract class NodeEvaluator {
|
|
}
|
|
|
|
protected Node getNode(int x, int y, int z) {
|
|
- return this.nodes.computeIfAbsent(Node.createHash(x, y, z), (l) -> {
|
|
- return new Node(x, y, z);
|
|
- });
|
|
+ return this.nodes.computeIfAbsent(Node.createHash(x, y, z), (l) -> new Node(x, y, z));
|
|
}
|
|
|
|
public abstract Node getStart();
|
|
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/Path.java b/src/main/java/net/minecraft/world/level/pathfinder/Path.java
|
|
index 2a335f277bd0e4b8ad0f60d8226eb8aaa80a871f..96765e6fe34ed5bce3ebe9859714d9bd805d7d22 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/Path.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/Path.java
|
|
@@ -21,7 +21,7 @@ public class Path {
|
|
private final BlockPos target;
|
|
private final float distToTarget;
|
|
private final boolean reached;
|
|
- public boolean hasNext() { return getNextNodeIndex() < this.nodes.size(); } // Paper
|
|
+ public synchronized boolean hasNext() { return getNextNodeIndex() < this.nodes.size(); } // Paper
|
|
|
|
public Path(List<Node> nodes, BlockPos target, boolean reachesTarget) {
|
|
this.nodes = nodes;
|
|
@@ -30,51 +30,51 @@ public class Path {
|
|
this.reached = reachesTarget;
|
|
}
|
|
|
|
- public void advance() {
|
|
+ public synchronized void advance() {
|
|
++this.nextNodeIndex;
|
|
}
|
|
|
|
- public boolean notStarted() {
|
|
+ public synchronized boolean notStarted() {
|
|
return this.nextNodeIndex <= 0;
|
|
}
|
|
|
|
- public boolean isDone() {
|
|
+ public synchronized boolean isDone() {
|
|
return this.nextNodeIndex >= this.nodes.size();
|
|
}
|
|
|
|
@Nullable
|
|
- public Node getEndNode() {
|
|
+ public synchronized Node getEndNode() {
|
|
return !this.nodes.isEmpty() ? this.nodes.get(this.nodes.size() - 1) : null;
|
|
}
|
|
|
|
- public Node getNode(int index) {
|
|
+ public synchronized Node getNode(int index) {
|
|
return this.nodes.get(index);
|
|
}
|
|
|
|
- public void truncateNodes(int length) {
|
|
+ public synchronized void truncateNodes(int length) {
|
|
if (this.nodes.size() > length) {
|
|
this.nodes.subList(length, this.nodes.size()).clear();
|
|
}
|
|
|
|
}
|
|
|
|
- public void replaceNode(int index, Node node) {
|
|
+ public synchronized void replaceNode(int index, Node node) {
|
|
this.nodes.set(index, node);
|
|
}
|
|
|
|
- public int getNodeCount() {
|
|
+ public synchronized int getNodeCount() {
|
|
return this.nodes.size();
|
|
}
|
|
|
|
- public int getNextNodeIndex() {
|
|
+ public synchronized int getNextNodeIndex() {
|
|
return this.nextNodeIndex;
|
|
}
|
|
|
|
- public void setNextNodeIndex(int nodeIndex) {
|
|
+ public synchronized void setNextNodeIndex(int nodeIndex) {
|
|
this.nextNodeIndex = nodeIndex;
|
|
}
|
|
|
|
- public Vec3 getEntityPosAtNode(Entity entity, int index) {
|
|
+ public synchronized Vec3 getEntityPosAtNode(Entity entity, int index) {
|
|
Node node = this.nodes.get(index);
|
|
double d = (double)node.x + (double)((int)(entity.getBbWidth() + 1.0F)) * 0.5D;
|
|
double e = (double)node.y;
|
|
@@ -82,28 +82,28 @@ public class Path {
|
|
return new Vec3(d, e, f);
|
|
}
|
|
|
|
- public BlockPos getNodePos(int index) {
|
|
+ public synchronized BlockPos getNodePos(int index) {
|
|
return this.nodes.get(index).asBlockPos();
|
|
}
|
|
|
|
- public Vec3 getNextEntityPos(Entity entity) {
|
|
+ public synchronized Vec3 getNextEntityPos(Entity entity) {
|
|
return this.getEntityPosAtNode(entity, this.nextNodeIndex);
|
|
}
|
|
|
|
- public BlockPos getNextNodePos() {
|
|
+ public synchronized BlockPos getNextNodePos() {
|
|
return this.nodes.get(this.nextNodeIndex).asBlockPos();
|
|
}
|
|
|
|
- public Node getNextNode() {
|
|
+ public synchronized Node getNextNode() {
|
|
return this.nodes.get(this.nextNodeIndex);
|
|
}
|
|
|
|
@Nullable
|
|
- public Node getPreviousNode() {
|
|
+ public synchronized Node getPreviousNode() {
|
|
return this.nextNodeIndex > 0 ? this.nodes.get(this.nextNodeIndex - 1) : null;
|
|
}
|
|
|
|
- public boolean sameAs(@Nullable Path o) {
|
|
+ public synchronized boolean sameAs(@Nullable Path o) {
|
|
if (o == null) {
|
|
return false;
|
|
} else if (o.nodes.size() != this.nodes.size()) {
|
|
@@ -121,7 +121,7 @@ public class Path {
|
|
}
|
|
}
|
|
|
|
- public boolean canReach() {
|
|
+ public synchronized boolean canReach() {
|
|
return this.reached;
|
|
}
|
|
|
|
@@ -133,16 +133,16 @@ public class Path {
|
|
}
|
|
|
|
@VisibleForDebug
|
|
- public Node[] getOpenSet() {
|
|
+ public synchronized Node[] getOpenSet() {
|
|
return this.openSet;
|
|
}
|
|
|
|
@VisibleForDebug
|
|
- public Node[] getClosedSet() {
|
|
+ public synchronized Node[] getClosedSet() {
|
|
return this.closedSet;
|
|
}
|
|
|
|
- public void writeToStream(FriendlyByteBuf buffer) {
|
|
+ public synchronized void writeToStream(FriendlyByteBuf buffer) {
|
|
if (this.targetNodes != null && !this.targetNodes.isEmpty()) {
|
|
buffer.writeBoolean(this.reached);
|
|
buffer.writeInt(this.nextNodeIndex);
|
|
@@ -213,15 +213,15 @@ public class Path {
|
|
}
|
|
|
|
@Override
|
|
- public String toString() {
|
|
+ public synchronized String toString() {
|
|
return "Path(length=" + this.nodes.size() + ")";
|
|
}
|
|
|
|
- public BlockPos getTarget() {
|
|
+ public synchronized BlockPos getTarget() {
|
|
return this.target;
|
|
}
|
|
|
|
- public float getDistToTarget() {
|
|
+ public synchronized float getDistToTarget() {
|
|
return this.distToTarget;
|
|
}
|
|
}
|
|
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..eee47eb38754766f5ca3ff98cc4f875a7afba686 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
|
@@ -1,21 +1,15 @@
|
|
package net.minecraft.world.level.pathfinder;
|
|
|
|
-import com.google.common.collect.ImmutableSet;
|
|
import com.google.common.collect.Lists;
|
|
-import com.google.common.collect.Sets;
|
|
-import java.util.Comparator;
|
|
-import java.util.List;
|
|
-import java.util.Map;
|
|
-import java.util.Optional;
|
|
-import java.util.Set;
|
|
-import java.util.function.Function;
|
|
-import java.util.stream.Collectors;
|
|
-import javax.annotation.Nullable;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.util.profiling.ProfilerFiller;
|
|
-import net.minecraft.util.profiling.metrics.MetricCategory;
|
|
import net.minecraft.world.entity.Mob;
|
|
import net.minecraft.world.level.PathNavigationRegion;
|
|
+import javax.annotation.Nullable;
|
|
+import java.util.Comparator;
|
|
+import java.util.List;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
|
|
public class PathFinder {
|
|
private static final float FUDGING = 1.5F;
|
|
@@ -31,7 +25,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();
|
|
@@ -76,10 +70,9 @@ public class PathFinder {
|
|
node.closed = true;
|
|
|
|
// Paper start - optimize collection
|
|
- for(int i1 = 0; i1 < positions.size(); i1++) {
|
|
- final Map.Entry<Target, BlockPos> entry = positions.get(i1);
|
|
+ for (final Map.Entry<Target, BlockPos> entry : positions) {
|
|
Target target = entry.getKey();
|
|
- if (node.distanceManhattan(target) <= (float)distance) {
|
|
+ if (node.distanceManhattan(target) <= (float) distance) {
|
|
target.setReached();
|
|
entryList.add(entry);
|
|
// Paper end
|
|
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) {
|
|
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));
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/ticks/LevelTicks.java b/src/main/java/net/minecraft/world/ticks/LevelTicks.java
|
|
index 5dea8414964e0d2d1fb15a6baa27227e9722bfc7..9953559a282afb6cb38b6cf495cc9250e3e13dae 100644
|
|
--- a/src/main/java/net/minecraft/world/ticks/LevelTicks.java
|
|
+++ b/src/main/java/net/minecraft/world/ticks/LevelTicks.java
|
|
@@ -1,10 +1,7 @@
|
|
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 co.m2ek4u.hearse.HearseConfig;
|
|
+import it.unimi.dsi.fastutil.longs.*;
|
|
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
|
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
|
import java.util.ArrayDeque;
|
|
@@ -15,10 +12,14 @@ import java.util.LongSummaryStatistics;
|
|
import java.util.PriorityQueue;
|
|
import java.util.Queue;
|
|
import java.util.Set;
|
|
+import java.util.concurrent.ConcurrentLinkedQueue;
|
|
+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;
|
|
+
|
|
+import it.unimi.dsi.fastutil.objects.ObjectSets;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.SectionPos;
|
|
@@ -28,24 +29,23 @@ import net.minecraft.world.level.ChunkPos;
|
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
|
|
|
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 static final Comparator<LevelChunkTicks<?>> CONTAINER_DRAIN_ORDER = (a, b) -> 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 Long2LongMap nextTickForContainer = Util.make(new Long2LongOpenHashMap(), (map) -> {
|
|
+ private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
|
|
+ private final Long2LongMap nextTickForContainer = Long2LongMaps.synchronize(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 ConcurrentLinkedQueue<>();
|
|
+ private final List<ScheduledTick<T>> alreadyRunThisTick = new CopyOnWriteArrayList<>();
|
|
+ private final Set<ScheduledTick<?>> toRunThisTickSet = ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH));
|
|
+ private static int taskLimit = HearseConfig.getInt("scheduled-task-limit-per-tick",65535);
|
|
+
|
|
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) {
|
|
@@ -123,7 +123,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 +135,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) {
|
|
@@ -186,24 +190,38 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
|
|
return this.toRunThisTick.size() < maxTicks;
|
|
}
|
|
|
|
+ private boolean allRunned;
|
|
+
|
|
private void runCollectedTicks(BiConsumer<BlockPos, T> ticker) {
|
|
+ int cycleCounter = 0;
|
|
while(!this.toRunThisTick.isEmpty()) {
|
|
+ if (cycleCounter >= taskLimit){
|
|
+ break;
|
|
+ }
|
|
ScheduledTick<T> scheduledTick = this.toRunThisTick.poll();
|
|
if (!this.toRunThisTickSet.isEmpty()) {
|
|
this.toRunThisTickSet.remove(scheduledTick);
|
|
}
|
|
-
|
|
this.alreadyRunThisTick.add(scheduledTick);
|
|
ticker.accept(scheduledTick.pos(), scheduledTick.type());
|
|
+ cycleCounter++;
|
|
}
|
|
-
|
|
+ if (cycleCounter >= taskLimit){
|
|
+ this.allRunned = false;
|
|
+ return;
|
|
+ }
|
|
+ this.allRunned = true;
|
|
}
|
|
|
|
private void cleanupAfterTick() {
|
|
- this.toRunThisTick.clear();
|
|
- this.containersToTick.clear();
|
|
+ if (this.allRunned){
|
|
+ this.toRunThisTick.clear();
|
|
+ synchronized (this.containersToTick){
|
|
+ this.containersToTick.clear();
|
|
+ }
|
|
+ this.toRunThisTickSet.clear();
|
|
+ }
|
|
this.alreadyRunThisTick.clear();
|
|
- this.toRunThisTickSet.clear();
|
|
}
|
|
|
|
@Override
|