9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-23 08:59:23 +00:00
Files
Leaf/patches/server/0043-Hearse-MC-code-changes.patch
2023-01-13 00:15:47 -05:00

1048 lines
50 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Sun, 8 Jan 2023 21:48:49 +0800
Subject: [PATCH] Hearse: MC code changes
Original license: MIT
Original project: https://github.com/NaturalCodeClub/HearseRewrite
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..c6f9fb3efb92de0879eab6389fabd531bb4cfcb2 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
@@ -1,7 +1,8 @@
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,14 +23,16 @@ 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();
+ final List<Short> copy = new ArrayList<>(positions);
+ this.positions = new short[copy.size()];
+ this.states = new BlockState[copy.size()];
+ for (int i = 0; i < copy.size(); i++) {
+ this.positions[i] = copy.get(i);
+ }
- 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();
+ for (int j = 0;j < this.positions.length;j++) {
+ short short0 = this.positions[j];
this.positions[j] = short0;
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/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
index bc46479fd0622a90fd98ac88f92b2840a22a2d04..e642b4a83687d03e55feb340452d608c53ae7cce 100644
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
@@ -2,19 +2,9 @@ package net.minecraft.server.level;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Pair;
-import it.unimi.dsi.fastutil.shorts.ShortOpenHashSet;
+import it.unimi.dsi.fastutil.shorts.ShortArraySet;
import it.unimi.dsi.fastutil.shorts.ShortSet;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicReferenceArray;
-import java.util.function.IntConsumer;
-import java.util.function.IntSupplier;
-import javax.annotation.Nullable;
-import net.minecraft.Util;
+import it.unimi.dsi.fastutil.shorts.ShortSets;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.Packet;
@@ -29,15 +19,14 @@ import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.chunk.ChunkAccess;
-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.LevelChunkSection;
-import net.minecraft.world.level.chunk.ProtoChunk;
+import net.minecraft.world.level.chunk.*;
import net.minecraft.world.level.lighting.LevelLightEngine;
-// CraftBukkit start
-import net.minecraft.server.MinecraftServer;
+import javax.annotation.Nullable;
+import java.util.BitSet;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
// CraftBukkit end
public class ChunkHolder {
@@ -233,7 +222,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] = ShortSets.synchronize(new ShortArraySet());
}
this.changedBlocksPerSection[i].add(SectionPos.sectionRelativePos(pos));
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index beb7c22cb63021f26c06f91050361e1b25fcc72d..10c7d776ca0d959541d3110c75ceb45a340278ac 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1,57 +1,25 @@
package net.minecraft.server.level;
-import co.aikar.timings.Timing; // Paper
import com.google.common.collect.ImmutableList;
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 io.papermc.paper.util.MCUtil;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-import it.unimi.dsi.fastutil.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.longs.*;
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 +31,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 +52,24 @@ 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;
-// CraftBukkit end
+import org.slf4j.Logger;
-import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
+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.*;
public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider {
@@ -153,7 +109,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
private final Queue<Runnable> unloadQueue;
int viewDistance;
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper
- public final ReferenceOpenHashSet<ChunkHolder> needsChangeBroadcasting = new ReferenceOpenHashSet<>();
+ public final ReferenceSet<ChunkHolder> needsChangeBroadcasting = ReferenceSets.synchronize(new ReferenceOpenHashSet<>());
// Paper - rewrite chunk system
// Paper start - optimise checkDespawn
@@ -295,9 +251,9 @@ 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.chunkTypeCache = new Long2ByteOpenHashMap();
- this.chunkSaveCooldowns = new Long2LongOpenHashMap();
+ this.entityMap = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap());
+ this.chunkTypeCache = Long2ByteMaps.synchronize(new Long2ByteOpenHashMap());
+ this.chunkSaveCooldowns = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
this.unloadQueue = Queues.newConcurrentLinkedQueue();
this.structureTemplateManager = structureTemplateManager;
Path path = session.getDimensionPath(world.dimension());
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
index 52cba8f68d274cce106304aef1249a95474d3238..a9ba8adc5f290f6e2820632bdae8e50165595706 100644
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
@@ -1,42 +1,20 @@
package net.minecraft.server.level;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import com.mojang.datafixers.util.Either;
import com.mojang.logging.LogUtils;
-import it.unimi.dsi.fastutil.longs.Long2ByteMap;
-import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
-import it.unimi.dsi.fastutil.longs.Long2IntMap;
-import it.unimi.dsi.fastutil.longs.Long2IntMaps;
-import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
-import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
-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.longs.*;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
-import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Iterator;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
-import javax.annotation.Nullable;
import net.minecraft.core.SectionPos;
import net.minecraft.util.SortedArraySet;
-import net.minecraft.util.thread.ProcessorHandle;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkStatus;
-import net.minecraft.world.level.chunk.LevelChunk;
import org.slf4j.Logger;
+import javax.annotation.Nullable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.Executor;
public abstract class DistanceManager {
@@ -52,7 +30,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 = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap());
// 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..a2935994edc279d880ff26dd5cc4e33f1105acc8 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -4,43 +4,19 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
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.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-import javax.annotation.Nullable;
+import it.unimi.dsi.fastutil.objects.ObjectArraySet;
+import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.Packet;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.VisibleForDebug;
-import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
-import net.minecraft.world.level.BlockGetter;
-import net.minecraft.world.level.ChunkPos;
-import net.minecraft.world.level.GameRules;
-import net.minecraft.world.level.Level;
-import net.minecraft.world.level.LightLayer;
-import net.minecraft.world.level.LocalMobCapCalculator;
-import net.minecraft.world.level.NaturalSpawner;
-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.ChunkSource;
-import net.minecraft.world.level.chunk.ChunkStatus;
-import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.*;
+import net.minecraft.world.level.chunk.*;
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
import net.minecraft.world.level.entity.ChunkStatusUpdateListener;
import net.minecraft.world.level.levelgen.RandomState;
@@ -48,7 +24,16 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
import net.minecraft.world.level.storage.DimensionDataStorage;
import net.minecraft.world.level.storage.LevelData;
import net.minecraft.world.level.storage.LevelStorageSource;
-import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
+
+import javax.annotation.Nullable;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
public class ServerChunkCache extends ChunkSource {
@@ -803,7 +788,7 @@ public class ServerChunkCache extends ChunkSource {
//gameprofilerfiller.popPush("broadcast"); // Purpur
//this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing // Purpur
if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) {
- ReferenceOpenHashSet<ChunkHolder> copy = this.chunkMap.needsChangeBroadcasting.clone();
+ ObjectSet<ChunkHolder> copy = new ObjectArraySet<>(this.chunkMap.needsChangeBroadcasting);
this.chunkMap.needsChangeBroadcasting.clear();
for (ChunkHolder holder : copy) {
holder.broadcastChanges(holder.getFullChunkNowUnchecked()); // LevelChunks are NEVER unloaded
diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java
index 660693c6dc0ef86f4013df980b6d0c11c03e46cd..1ea9699ce1f77a551a45fc06dad55df4cc1a4f4d 100644
--- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java
+++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java
@@ -1,14 +1,9 @@
package net.minecraft.server.level;
-import com.mojang.datafixers.util.Pair;
+import ca.spottedleaf.starlight.common.light.StarLightEngine;
import com.mojang.logging.LogUtils;
-import it.unimi.dsi.fastutil.objects.ObjectArrayList;
-import it.unimi.dsi.fastutil.objects.ObjectList;
-import it.unimi.dsi.fastutil.objects.ObjectListIterator;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.IntSupplier;
-import javax.annotation.Nullable;
+import io.papermc.paper.util.CoordinateUtils;
+import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
@@ -17,21 +12,17 @@ import net.minecraft.util.thread.ProcessorMailbox;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.DataLayer;
-import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LightChunkGetter;
+import net.minecraft.world.level.lighting.LayerLightEventListener;
import net.minecraft.world.level.lighting.LevelLightEngine;
import org.slf4j.Logger;
-// Paper start
-import ca.spottedleaf.starlight.common.light.StarLightEngine;
-import io.papermc.paper.util.CoordinateUtils;
+import javax.annotation.Nullable;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.IntSupplier;
import java.util.function.Supplier;
-import net.minecraft.world.level.lighting.LayerLightEventListener;
-import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
-import it.unimi.dsi.fastutil.longs.LongArrayList;
-import it.unimi.dsi.fastutil.longs.LongIterator;
-import net.minecraft.world.level.chunk.ChunkStatus;
// Paper end
public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable {
@@ -145,20 +136,30 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl
return;
}
- final int references = this.chunksBeingWorkedOn.addTo(key, 1);
+ int references;
+ synchronized (this.chunksBeingWorkedOn){
+ references = this.chunksBeingWorkedOn.addTo(key, 1);
+ }
if (references == 0) {
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
world.getChunkSource().addRegionTicket(ca.spottedleaf.starlight.common.light.StarLightInterface.CHUNK_WORK_TICKET, pos, 0, pos);
}
updateFuture.thenAcceptAsync((final Void ignore) -> {
- final int newReferences = this.chunksBeingWorkedOn.get(key);
+ int newReferences;
+ synchronized (this.chunksBeingWorkedOn){
+ newReferences = this.chunksBeingWorkedOn.get(key);
+ }
if (newReferences == 1) {
- this.chunksBeingWorkedOn.remove(key);
+ synchronized (this.chunksBeingWorkedOn){
+ this.chunksBeingWorkedOn.remove(key);
+ }
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
world.getChunkSource().removeRegionTicket(ca.spottedleaf.starlight.common.light.StarLightInterface.CHUNK_WORK_TICKET, pos, 0, pos);
} else {
- this.chunksBeingWorkedOn.put(key, newReferences - 1);
+ synchronized (this.chunksBeingWorkedOn){
+ this.chunksBeingWorkedOn.put(key, newReferences - 1);
+ }
}
}, world.getChunkSource().chunkMap.mainThreadExecutor).whenComplete((final Void ignore, final Throwable thr) -> {
if (thr != null) {
diff --git a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
index 50a9f33aa31e9273c7c52d4bb2b02f0f884f7ba5..d5802cfe08f92b55ff1fd41648abda9ef2b7dd20 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;
@@ -59,12 +61,16 @@ public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
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 this.allInstances.stream().filter(typeClass::isInstance).collect(toList());
});
- return Collections.unmodifiableCollection(list);
+ return (Collection<S>) Collections.unmodifiableCollection(list);
}
}
+ public static <T> Collector<T, ?, List<T>> toList() {
+ return Collectors.toCollection(CopyOnWriteArrayList::new);
+ }
+
@Override
public Iterator<T> iterator() {
return (Iterator<T>)(this.allInstances.isEmpty() ? Collections.emptyIterator() : Iterators.unmodifiableIterator(this.allInstances.iterator()));
diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
index 83701fbfaa56a232593ee8f11a3afb8941238bfa..0c70810edace99bb5037d927388e055a514fcbde 100644
--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
+++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
@@ -8,6 +8,7 @@ import java.util.Queue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.StampedLock;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import net.minecraft.util.profiling.metrics.MetricCategory;
@@ -20,6 +21,7 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
private final String name;
private static final Logger LOGGER = LogUtils.getLogger();
private final Queue<R> pendingRunnables = Queues.newConcurrentLinkedQueue();
+ private final StampedLock lock = new StampedLock();
private int blockingCount;
protected BlockableEventLoop(String name) {
@@ -42,7 +44,12 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
}
public int getPendingTasksCount() {
- return this.pendingRunnables.size();
+ final long id = this.lock.readLock();
+ try{
+ return this.pendingRunnables.size();
+ }finally {
+ this.lock.unlockRead(id);
+ }
}
@Override
@@ -88,7 +95,12 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
@Override
public void tell(R runnable) {
- this.pendingRunnables.add(runnable);
+ final long id = this.lock.writeLock();
+ try {
+ this.pendingRunnables.add(runnable);
+ }finally {
+ this.lock.unlockWrite(id);
+ }
LockSupport.unpark(this.getRunningThread());
}
@@ -107,7 +119,12 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
}
protected void dropAllTasks() {
- this.pendingRunnables.clear();
+ final long id = this.lock.writeLock();
+ try {
+ this.pendingRunnables.clear();
+ }finally {
+ this.lock.unlockWrite(id);
+ }
}
protected void runAllTasks() {
@@ -117,14 +134,19 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
}
public boolean pollTask() {
- R runnable = this.pendingRunnables.peek();
- if (runnable == null) {
- return false;
- } else if (this.blockingCount == 0 && !this.shouldRun(runnable)) {
- return false;
- } else {
- this.doRunTask(this.pendingRunnables.remove());
- return true;
+ final long id = this.lock.writeLock();
+ try {
+ R runnable = this.pendingRunnables.peek();
+ if (runnable == null) {
+ return false;
+ } else if (this.blockingCount == 0 && !this.shouldRun(runnable)) {
+ return false;
+ } else {
+ this.doRunTask(this.pendingRunnables.remove());
+ return true;
+ }
+ }finally {
+ this.lock.unlockWrite(id);
}
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 99912ae883227e1c0a0adc1edbb4c4baee4fe2bc..f33476a35706d7a236fe3bb178d166d568c07674 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -164,76 +164,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
// Paper start
- public static RandomSource SHARED_RANDOM = new RandomRandomSource();
- private static final class RandomRandomSource extends java.util.Random implements net.minecraft.world.level.levelgen.BitRandomSource {
- private boolean locked = false;
-
- @Override
- public synchronized void setSeed(long seed) {
- if (locked) {
- LOGGER.error("Ignoring setSeed on Entity.SHARED_RANDOM", new Throwable());
- } else {
- super.setSeed(seed);
- locked = true;
- }
- }
-
- @Override
- public RandomSource fork() {
- return new net.minecraft.world.level.levelgen.LegacyRandomSource(this.nextLong());
- }
-
- @Override
- public net.minecraft.world.level.levelgen.PositionalRandomFactory forkPositional() {
- return new net.minecraft.world.level.levelgen.LegacyRandomSource.LegacyPositionalRandomFactory(this.nextLong());
- }
-
- // these below are added to fix reobf issues that I don't wanna deal with right now
- @Override
- public int next(int bits) {
- return super.next(bits);
- }
-
- @Override
- public int nextInt(int origin, int bound) {
- return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(origin, bound);
- }
-
- @Override
- public long nextLong() {
- return net.minecraft.world.level.levelgen.BitRandomSource.super.nextLong();
- }
-
- @Override
- public int nextInt() {
- return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt();
- }
-
- @Override
- public int nextInt(int bound) {
- return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(bound);
- }
-
- @Override
- public boolean nextBoolean() {
- return net.minecraft.world.level.levelgen.BitRandomSource.super.nextBoolean();
- }
-
- @Override
- public float nextFloat() {
- return net.minecraft.world.level.levelgen.BitRandomSource.super.nextFloat();
- }
-
- @Override
- public double nextDouble() {
- return net.minecraft.world.level.levelgen.BitRandomSource.super.nextDouble();
- }
-
- @Override
- public double nextGaussian() {
- return super.nextGaussian();
- }
- }
+ public static RandomSource SHARED_RANDOM = RandomSource.create();
// Paper end
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper
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..00f7b58db5948f4d7c7f07736d8fcf1972009c77 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,22 @@
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.Iterator;
+import java.util.Set;
import java.util.function.Consumer;
-import javax.annotation.Nullable;
+import it.unimi.dsi.fastutil.objects.ObjectArraySet;
+import it.unimi.dsi.fastutil.objects.ObjectSets;
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
-
- }
+ public final Set<Entity> entities = ObjectSets.synchronize(new ObjectArraySet<>());
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,16 +26,8 @@ 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();
+ for (Entity entity : this.entities) {
+ action.accept(entity);
}
// Paper end - replace with better logic, do not delay removals/additions
}
diff --git a/src/main/java/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/levelgen/LegacyRandomSource.java b/src/main/java/net/minecraft/world/level/levelgen/LegacyRandomSource.java
index daa03360dd7044f10b20f36023b305dc7e0bb7df..35de9e9a9d211b16a8b945bc512c128709ec6bfc 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();
}
@@ -61,21 +61,21 @@ public class LegacyRandomSource implements BitRandomSource {
}
@Override
- public RandomSource at(int x, int y, int z) {
+ public synchronized RandomSource at(int x, int y, int z) {
long l = Mth.getSeed(x, y, z);
long m = l ^ this.seed;
return new LegacyRandomSource(m);
}
@Override
- public RandomSource fromHashOf(String seed) {
+ public synchronized RandomSource fromHashOf(String seed) {
int i = seed.hashCode();
return new LegacyRandomSource((long)i ^ this.seed);
}
@VisibleForTesting
@Override
- public void parityConfigString(StringBuilder info) {
+ public synchronized void parityConfigString(StringBuilder info) {
info.append("LegacyPositionalRandomFactory{").append(this.seed).append("}");
}
}
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..88d78f77740ee436fedd5159f8bafe91c1eb5ec1 100644
--- a/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java
+++ b/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java
@@ -1,17 +1,16 @@
package net.minecraft.world.level.lighting;
-import it.unimi.dsi.fastutil.longs.Long2ByteMap;
-import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
-import it.unimi.dsi.fastutil.longs.LongArrayList;
-import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
-import it.unimi.dsi.fastutil.longs.LongList;
+import it.unimi.dsi.fastutil.longs.*;
+
+import java.util.Deque;
+import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.LongPredicate;
import net.minecraft.util.Mth;
public abstract class DynamicGraphMinFixedPoint {
private static final int NO_COMPUTED_LEVEL = 255;
private final int levelCount;
- private final LongLinkedOpenHashSet[] queues;
+ private final Deque<Long>[] queues;
private final Long2ByteMap computedLevels;
private int firstQueuedLevel;
private volatile boolean hasWork;
@@ -21,17 +20,10 @@ public abstract class DynamicGraphMinFixedPoint {
throw new IllegalArgumentException("Level count must be < 254.");
} else {
this.levelCount = levelCount;
- this.queues = new LongLinkedOpenHashSet[levelCount];
+ this.queues = new Deque[levelCount];
for(int i = 0; i < levelCount; ++i) {
- this.queues[i] = new LongLinkedOpenHashSet(expectedLevelSize, 0.5F) {
- protected void rehash(int i) {
- if (i > expectedLevelSize) {
- super.rehash(i);
- }
-
- }
- };
+ this.queues[i] = new ConcurrentLinkedDeque();
}
this.computedLevels = new Long2ByteOpenHashMap(expectedTotalSize, 0.5F) {
@@ -191,8 +183,8 @@ public abstract class DynamicGraphMinFixedPoint {
} else {
while(this.firstQueuedLevel < this.levelCount && maxSteps > 0) {
--maxSteps;
- LongLinkedOpenHashSet longLinkedOpenHashSet = this.queues[this.firstQueuedLevel];
- long l = longLinkedOpenHashSet.removeFirstLong();
+ Deque<Long> longLinkedOpenHashSet = this.queues[this.firstQueuedLevel];
+ long l = longLinkedOpenHashSet.removeFirst();
int i = Mth.clamp(this.getLevel(l), 0, this.levelCount - 1);
if (longLinkedOpenHashSet.isEmpty()) {
this.checkFirstQueuedLevel(this.levelCount);
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..a097e00bd62f53630568f68854d3a34300012277 100644
--- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
+++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
@@ -4,6 +4,8 @@ import com.mojang.logging.LogUtils;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.StampedLock;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -17,9 +19,11 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
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 List<CollectingNeighborUpdater.NeighborUpdates> addedThisLayer = new CopyOnWriteArrayList<>();
private int count = 0;
+ private final StampedLock lock = new StampedLock();
+
public CollectingNeighborUpdater(Level world, int maxChainDepth) {
this.level = world;
this.maxChainedNeighborUpdates = maxChainDepth;
@@ -49,14 +53,19 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
boolean bl = this.count > 0;
boolean bl2 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates;
++this.count;
- if (!bl2) {
- if (bl) {
- this.addedThisLayer.add(entry);
- } else {
- this.stack.push(entry);
+ final long lockId = this.lock.writeLock();
+ try {
+ if (!bl2) {
+ if (bl) {
+ this.addedThisLayer.add(entry);
+ } else {
+ this.stack.push(entry);
+ }
+ } else if (this.count - 1 == this.maxChainedNeighborUpdates) {
+ LOGGER.error("Too many chained neighbor updates. Skipping the rest. First skipped position: " + pos.toShortString());
}
- } else if (this.count - 1 == this.maxChainedNeighborUpdates) {
- LOGGER.error("Too many chained neighbor updates. Skipping the rest. First skipped position: " + pos.toShortString());
+ }finally {
+ this.lock.unlockWrite(lockId);
}
if (!bl) {
@@ -66,28 +75,31 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
}
private void runUpdates() {
+ final long lockid = this.lock.writeLock();
try {
- while(!this.stack.isEmpty() || !this.addedThisLayer.isEmpty()) {
- for(int i = this.addedThisLayer.size() - 1; i >= 0; --i) {
- this.stack.push(this.addedThisLayer.get(i));
- }
-
- this.addedThisLayer.clear();
- CollectingNeighborUpdater.NeighborUpdates neighborUpdates = this.stack.peek();
-
- while(this.addedThisLayer.isEmpty()) {
- if (!neighborUpdates.runNext(this.level)) {
- this.stack.pop();
- break;
+ try {
+ while(!this.stack.isEmpty() || !this.addedThisLayer.isEmpty()) {
+ for(int i = this.addedThisLayer.size() - 1; i >= 0; --i) {
+ this.stack.push(this.addedThisLayer.get(i));
+ }
+ this.addedThisLayer.clear();
+ CollectingNeighborUpdater.NeighborUpdates neighborUpdates = this.stack.peek();
+
+ while(this.addedThisLayer.isEmpty()) {
+ if (!neighborUpdates.runNext(this.level)) {
+ this.stack.pop();
+ break;
+ }
}
}
+ } finally {
+ this.stack.clear();
+ this.addedThisLayer.clear();
+ this.count = 0;
}
- } finally {
- this.stack.clear();
- this.addedThisLayer.clear();
- this.count = 0;
+ }finally {
+ this.lock.unlockWrite(lockid);
}
-
}
static record FullNeighborUpdate(BlockState state, BlockPos pos, Block block, BlockPos neighborPos, boolean movedByPiston) implements CollectingNeighborUpdater.NeighborUpdates {