9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-23 00:49:31 +00:00
Files
Leaf/patches/server/0046-Hearse-MC-Code-changes.patch
2023-01-27 08:39:13 -05:00

2844 lines
143 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: wangxyper <wangxyper@163.com>
Date: Sun, 15 Jan 2023 09:57:50 +0800
Subject: [PATCH] Hearse: MC Code changes
Original license: MIT
Original project: https://github.com/Era4FunMC/Hearse
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/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 3b7e4b724e86518ea57f5ed5ef0b8b3741d10f6f..42599340856aa5ffcfae2281684174ca4dee289a 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1,10 +1,11 @@
package net.minecraft.server;
+import co.earthme.hearse.Hearse;
+import co.earthme.hearse.HearseConfig;
+import co.earthme.hearse.server.ServerEntityTickHook;
+import co.earthme.hearse.server.ServerLevelTickHook;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
-import 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;
@@ -85,7 +86,6 @@ import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
-import net.minecraft.server.level.TicketType;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
import net.minecraft.server.network.ServerConnectionListener;
@@ -109,17 +109,14 @@ import net.minecraft.util.NativeModuleLister;
import net.minecraft.util.ProgressListener;
import net.minecraft.util.RandomSource;
import net.minecraft.util.SignatureValidator;
-import net.minecraft.util.Unit;
import net.minecraft.util.datafix.DataFixers;
import net.minecraft.util.profiling.EmptyProfileResults;
import net.minecraft.util.profiling.ProfileResults;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.util.profiling.ResultField;
-import net.minecraft.util.profiling.SingleTickProfiler;
import net.minecraft.util.profiling.jfr.JvmProfiler;
import net.minecraft.util.profiling.jfr.callback.ProfiledDuration;
import net.minecraft.util.profiling.metrics.profiling.ActiveMetricsRecorder;
-import net.minecraft.util.profiling.metrics.profiling.InactiveMetricsRecorder;
import net.minecraft.util.profiling.metrics.profiling.MetricsRecorder;
import net.minecraft.util.profiling.metrics.profiling.ServerMetricsSamplersProvider;
import net.minecraft.util.profiling.metrics.storage.MetricsPersister;
@@ -183,12 +180,6 @@ import net.minecraft.world.level.levelgen.PatrolSpawner;
import net.minecraft.world.level.levelgen.PhantomSpawner;
import net.minecraft.world.level.levelgen.WorldDimensions;
import net.minecraft.world.level.levelgen.presets.WorldPresets;
-import org.bukkit.Bukkit;
-import org.bukkit.craftbukkit.CraftServer;
-import org.bukkit.craftbukkit.Main;
-import org.bukkit.craftbukkit.util.CraftChatMessage;
-import org.bukkit.craftbukkit.util.LazyPlayerSet;
-import org.bukkit.event.player.AsyncPlayerChatPreviewEvent;
import org.bukkit.event.server.ServerLoadEvent;
// CraftBukkit end
@@ -233,7 +224,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private String localIp;
private int port;
private final LayeredRegistryAccess<RegistryLayer> registries;
- private Map<ResourceKey<Level>, ServerLevel> levels;
+ public Map<ResourceKey<Level>, ServerLevel> levels;
private PlayerList playerList;
private volatile boolean running;
private volatile boolean isRestarting = false; // Paper - flag to signify we're attempting to restart
@@ -922,10 +913,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper
// Paper start - kill main thread, and kill it hard
+ Hearse.onServerStop();//Hearse
shutdownThread = Thread.currentThread();
org.spigotmc.WatchdogThread.doStop(); // Paper
if (!isSameThread()) {
- MinecraftServer.LOGGER.info("Stopping main thread (Ignore any thread death message you see! - DO NOT REPORT THREAD DEATH TO LEAF)"); // Leaf
+ MinecraftServer.LOGGER.info("Stopping main thread (Ignore any thread death message you see! - DO NOT REPORT THREAD DEATH TO LEAF)"); // Hearse // Leaf
while (this.getRunningThread().isAlive()) {
this.getRunningThread().stop();
try {
@@ -1129,6 +1121,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
Arrays.fill( recentTps, 20 );
long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop
lastTick = start - TICK_TIME; // Paper
+ ServerLevelTickHook.initWorker(); //Hearse
while (this.running) {
// Paper start - rewrite chunk system
// guarantee that nothing can stop the server from halting if it can at least still tick
@@ -1404,9 +1397,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
//isOversleep = false;MinecraftTimings.serverOversleep.stopTiming(); // Purpur
// Paper end
new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper
-
+ ServerEntityTickHook.callTickStart();
++this.tickCount;
this.tickChildren(shouldKeepTicking);
+
if (i - this.lastServerStatus >= 5000000000L) {
this.lastServerStatus = i;
this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount()));
@@ -1522,11 +1516,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
@@ -1541,35 +1533,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// CraftBukkit end */
//this.profiler.push("tick"); // Purpur
-
- try {
- //worldserver.timings.doTick.startTiming(); // Spigot // Purpur
- worldserver.tick(shouldKeepTicking);
- // Paper start
- for (final io.papermc.paper.chunk.SingleThreadChunkRegionManager regionManager : worldserver.getChunkSource().chunkMap.regionManagers) {
- regionManager.recalculateRegions();
- }
- // Paper end
- //worldserver.timings.doTick.stopTiming(); // Spigot // Purpur
- } catch (Throwable throwable) {
- // Spigot Start
- CrashReport crashreport;
- try {
- crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
- } catch (Throwable t) {
- if (throwable instanceof ThreadDeath) { throw (ThreadDeath)throwable; } // Paper
- throw new RuntimeException("Error generating crash report", t);
- }
- // Spigot End
-
- worldserver.fillReportDetails(crashreport);
- throw new ReportedException(crashreport);
- }
-
- //this.profiler.pop(); // Purpur
- //this.profiler.pop(); // Purpur
- worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
+ ServerLevelTickHook.callWorldTick(worldserver,shouldKeepTicking);
}
+ ServerLevelTickHook.awaitWorldTicKTasks();
this.isIteratingOverLevels = false; // Paper
//this.profiler.popPush("connection"); // Purpur
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 1cc5cf3dcf33e89092b2aa689170c775007e4e4a..9f7516bb5a5c4345584e1fe1412963c1c8d8951d 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -1,5 +1,6 @@
package net.minecraft.server.dedicated;
+import co.earthme.hearse.Hearse;
import com.google.common.collect.Lists;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.DataFixer;
@@ -226,6 +227,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
gg.pufferfish.pufferfish.PufferfishCommand.init(); // Pufferfish
org.dreeam.leaf.LeafConfig.load(); // Leaf
+ Hearse.initAll(); //Hearse
+
this.setPvpAllowed(dedicatedserverproperties.pvp);
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
this.setMotd(dedicatedserverproperties.motd);
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
index bc46479fd0622a90fd98ac88f92b2840a22a2d04..ebb1c69f905ef3c948a65c9f095244b7e663b3a9 100644
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
@@ -2,19 +2,8 @@ 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.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 net.himeki.mcmtfabric.parallelised.fastutil.ConcurrentShortHashSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.Packet;
@@ -29,15 +18,15 @@ 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] = new ConcurrentShortHashSet();
}
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..dfb747eba6bf7088af0ff400da169de00a076365 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1,57 +1,22 @@
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 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 +28,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 +49,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 {
@@ -147,13 +100,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,ChunkMap.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,9 +248,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 = Maps.newConcurrentMap();
+ 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());
@@ -1183,8 +1136,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot
// Paper start - ignore and warn about illegal addEntity calls instead of crashing server
if (!entity.valid || entity.level != this.level || this.entityMap.containsKey(entity.getId())) {
- LOGGER.error("Illegal ChunkMap::addEntity for world " + this.level.getWorld().getName()
- + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable());
+ LOGGER.error("Illegal ChunkMap::addEntity for world " + this.level.getWorld().getName() + ": " + entity + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""));
return;
}
if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Delay adding to tracker until after list packets
@@ -1209,11 +1161,8 @@ 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 +1180,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 +1227,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..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..e311724d2e723115bc9549a61e6206a8aed835d8 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -4,43 +4,22 @@ 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.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+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 +27,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 {
@@ -72,8 +60,7 @@ public class ServerChunkCache extends ChunkSource {
@VisibleForDebug
private NaturalSpawner.SpawnState lastSpawnState;
// Paper start
- final com.destroystokyo.paper.util.concurrent.WeakSeqLock loadedChunkMapSeqLock = new com.destroystokyo.paper.util.concurrent.WeakSeqLock();
- final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<LevelChunk> loadedChunkMap = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>(8192, 0.5f);
+ private final Long2ObjectMap<LevelChunk> loadedChunkMap = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>(8192, 0.5f));
private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4];
@@ -85,12 +72,7 @@ public class ServerChunkCache extends ChunkSource {
}
public void addLoadedChunk(LevelChunk chunk) {
- this.loadedChunkMapSeqLock.acquireWrite();
- try {
- this.loadedChunkMap.put(chunk.coordinateKey, chunk);
- } finally {
- this.loadedChunkMapSeqLock.releaseWrite();
- }
+ this.loadedChunkMap.put(chunk.coordinateKey, chunk);
// rewrite cache if we have to
// we do this since we also cache null chunks
@@ -100,13 +82,7 @@ public class ServerChunkCache extends ChunkSource {
}
public void removeLoadedChunk(LevelChunk chunk) {
- this.loadedChunkMapSeqLock.acquireWrite();
- try {
- this.loadedChunkMap.remove(chunk.coordinateKey);
- } finally {
- this.loadedChunkMapSeqLock.releaseWrite();
- }
-
+ this.loadedChunkMap.remove(chunk.coordinateKey);
// rewrite cache if we have to
// we do this since we also cache null chunks
int cacheKey = getChunkCacheKey(chunk.locX, chunk.locZ);
@@ -375,22 +351,7 @@ public class ServerChunkCache extends ChunkSource {
return this.getChunkAtIfLoadedMainThread(x, z);
}
- LevelChunk ret = null;
- long readlock;
- do {
- readlock = this.loadedChunkMapSeqLock.acquireRead();
- try {
- ret = this.loadedChunkMap.get(k);
- } catch (Throwable thr) {
- if (thr instanceof ThreadDeath) {
- throw (ThreadDeath)thr;
- }
- // re-try, this means a CME occurred...
- continue;
- }
- } while (!this.loadedChunkMapSeqLock.tryReleaseRead(readlock));
-
- return ret;
+ return this.loadedChunkMap.get(k);
}
// Paper end
// Paper start - async chunk io
@@ -451,7 +412,7 @@ public class ServerChunkCache extends ChunkSource {
// Paper end
com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x1, z1); // Paper - sync load info
//this.level.timings.syncChunkLoad.startTiming(); // Paper // Purpur
- chunkproviderserver_b.managedBlock(completablefuture::isDone);
+ chunkproviderserver_b.managedBlock(completablefuture::isDone);
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.popChunkWait(); // Paper - async chunk debug // Paper - rewrite chunk system
//this.level.timings.syncChunkLoad.stopTiming(); // Paper // Purpur
} // Paper
@@ -510,6 +471,7 @@ public class ServerChunkCache extends ChunkSource {
// Paper start - add isUrgent - old sig left in place for dirty nms plugins
return getChunkFutureMainThread(chunkX, chunkZ, leastStatus, create, false);
}
+
private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create, boolean isUrgent) {
// Paper start - rewrite chunk system
io.papermc.paper.util.TickThread.ensureTickThread(this.level, chunkX, chunkZ, "Scheduling chunk load off-main");
@@ -803,7 +765,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 +810,10 @@ public class ServerChunkCache extends ChunkSource {
if (chunkMap.playerMobDistanceMap != null && _pufferfish_spawnCountsReady.getAndSet(false)) {
net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> {
int mapped = distanceManager.getNaturalSpawnChunkCount();
- io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator<Entity> objectiterator =
- level.entityTickList.entities.iterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS);
+ Iterator<Entity> objectiterator = level.entityTickList.entities.iterator();
gg.pufferfish.pufferfish.util.IterableWrapper<Entity> wrappedIterator =
new gg.pufferfish.pufferfish.util.IterableWrapper<>(objectiterator);
lastSpawnState = NaturalSpawner.createState(mapped, wrappedIterator, this::getFullChunk, null, true);
- objectiterator.finishedIterating();
_pufferfish_spawnCountsReady.set(true);
});
}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 03b8ef3409fd5f7a4d4b06e13cf8eb22b3bbf8a1..39c3aaf91514bd8a2f9f04496e25a6253442939f 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1,69 +1,35 @@
package net.minecraft.server.level;
+import co.aikar.timings.TimingHistory;
+import co.earthme.hearse.concurrent.WorkerThread;
+import co.earthme.hearse.server.ServerEntityTickHook;
import com.google.common.annotations.VisibleForTesting;
-import co.aikar.timings.TimingHistory; // Paper
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.util.Pair;
import com.mojang.logging.LogUtils;
+import io.papermc.paper.util.MCUtil;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.longs.LongSets;
import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
-import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
-import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.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 +37,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 +57,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 +73,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 +101,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 {
@@ -192,7 +146,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
public final ServerChunkCache chunkSource;
private final MinecraftServer server;
public final PrimaryLevelData serverLevelData; // CraftBukkit - type
- final EntityTickList entityTickList;
+ public final EntityTickList entityTickList;
//public final PersistentEntitySectionManager<Entity> entityManager; // Paper - rewrite chunk system
private final GameEventDispatcher gameEventDispatcher;
public boolean noSave;
@@ -204,7 +158,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,7 +223,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
public final void loadChunksForMoveAsync(AABB axisalignedbb, ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority,
java.util.function.Consumer<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) {
- if (Thread.currentThread() != this.thread) {
+ if (Thread.currentThread() != this.thread && !WorkerThread.isWorker()) {
this.getChunkSource().mainThreadProcessor.execute(() -> {
this.loadChunksForMoveAsync(axisalignedbb, priority, onLoad);
});
@@ -536,10 +490,10 @@ public class ServerLevel extends Level implements WorldGenLevel {
this.entityTickList = new EntityTickList();
this.blockTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded, this.getProfilerSupplier());
this.fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded, this.getProfilerSupplier());
- this.navigatingMobs = new ObjectOpenHashSet();
- this.blockEvents = new ObjectLinkedOpenHashSet();
- this.blockEventsToReschedule = new ArrayList(64);
- this.dragonParts = new Int2ObjectOpenHashMap();
+ this.navigatingMobs = Sets.newConcurrentHashSet();
+ this.blockEvents = new ConcurrentLinkedDeque<>();
+ this.blockEventsToReschedule = Collections.synchronizedList(new ArrayList(64));
+ this.dragonParts = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap());
this.tickTime = flag1;
this.server = minecraftserver;
this.customSpawners = list;
@@ -691,71 +645,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
//timings.doSounds.stopTiming(); // Spigot // Purpur
this.handlingTick = false;
//gameprofilerfiller.pop(); // Purpur
- boolean flag = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
-
- if (flag) {
- this.resetEmptyTime();
- }
-
- if (flag || this.emptyTime++ < 300) {
- //gameprofilerfiller.push("entities"); // Purpur
- //timings.tickEntities.startTiming(); // Spigot // Purpur
- if (this.dragonFight != null) {
- //gameprofilerfiller.push("dragonFight"); // Purpur
- this.dragonFight.tick();
- //gameprofilerfiller.pop(); // Purpur
- }
-
- org.spigotmc.ActivationRange.activateEntities(this); // Spigot
- //timings.entityTick.startTiming(); // Spigot // Purpur
- this.entityTickList.forEach((entity) -> {
- entity.activatedPriorityReset = false; // Pufferfish - DAB
- if (!entity.isRemoved()) {
- if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed
- entity.discard();
- } else {
- //gameprofilerfiller.push("checkDespawn"); // Purpur
- entity.checkDespawn();
- //gameprofilerfiller.pop(); // Purpur
- if (true || this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { // Paper - now always true if in the ticking list
- Entity entity1 = entity.getVehicle();
-
- if (entity1 != null) {
- if (!entity1.isRemoved() && entity1.hasPassenger(entity)) {
- return;
- }
-
- entity.stopRiding();
- }
-
- //gameprofilerfiller.push("tick"); // Purpur
- // Pufferfish start - copied from this.guardEntityTick
- try {
- this.tickNonPassenger(entity); // Pufferfish - changed
- MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick
- } catch (Throwable throwable) {
- if (throwable instanceof ThreadDeath) throw throwable; // Paper
- // Paper start - Prevent tile entity and entity crashes
- final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
- MinecraftServer.LOGGER.error(msg, throwable);
- getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable)));
- entity.discard();
- // Paper end
- }
- // Pufferfish end
- //gameprofilerfiller.pop(); // Purpur
- }
- }
- }
- });
- //timings.entityTick.stopTiming(); // Spigot // Purpur
- //timings.tickEntities.stopTiming(); // Spigot // Purpur
- //gameprofilerfiller.pop(); // Purpur
- this.tickBlockEntities();
+ this.resetEmptyTime();
+ if (this.dragonFight != null) {
+ this.dragonFight.tick();
}
-
- //gameprofilerfiller.push("entityManagement"); // Purpur
- //this.entityManager.tick(); // Paper - rewrite chunk system
+ org.spigotmc.ActivationRange.activateEntities(this); // Spigot
+ this.entityTickList.forEach((entity) -> {
+ ServerEntityTickHook.callAsyncEntityTick(entity,this);
+ });
+ this.tickBlockEntities();
}
@Override
@@ -794,7 +692,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
- private boolean shouldDiscardEntity(Entity entity) {
+ public boolean shouldDiscardEntity(Entity entity) {
return !this.server.isSpawningAnimals() && (entity instanceof Animal || entity instanceof WaterAnimal) ? true : !this.server.areNpcsEnabled() && entity instanceof Npc;
}
@@ -993,7 +891,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");
@@ -1228,13 +1126,10 @@ public class ServerLevel extends Level implements WorldGenLevel {
} else { entity.inactiveTick(); } // Paper - EAR 2
//this.getProfiler().pop(); // Purpur
//} finally { timer.stopTiming(); } // Paper - timings // Purpur
- Iterator iterator = entity.getPassengers().iterator();
-
- while (iterator.hasNext()) {
- Entity entity1 = (Entity) iterator.next();
- this.tickPassenger(entity, entity1);
- }
+ for (Entity entity1 : entity.getPassengers()) {
+ this.tickPassenger(entity, entity1);
+ }
// } finally { timer.stopTiming(); } // Paper - timings - move up
// Paper start - log detailed entity tick information
} finally {
@@ -1273,11 +1168,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
// Paper end - EAR 2
//gameprofilerfiller.pop(); // Purpur
- Iterator iterator = passenger.getPassengers().iterator();
-
- while (iterator.hasNext()) {
- Entity entity2 = (Entity) iterator.next();
+ for (Entity entity2 : passenger.getPassengers()) {
this.tickPassenger(passenger, entity2);
}
@@ -1661,56 +1553,56 @@ public class ServerLevel extends Level implements WorldGenLevel {
@Override
public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) {
- if (this.isUpdatingNavigations) {
- String s = "recursive call to sendBlockUpdated";
+ synchronized (this.navigatingMobs){
+ if (this.isUpdatingNavigations) {
+ return;
+ }
- Util.logAndPauseIfInIde("recursive call to sendBlockUpdated", new IllegalStateException("recursive call to sendBlockUpdated"));
- }
+ this.getChunkSource().blockChanged(pos);
+ if(this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates
+ VoxelShape voxelshape = oldState.getCollisionShape(this, pos);
+ VoxelShape voxelshape1 = newState.getCollisionShape(this, pos);
- this.getChunkSource().blockChanged(pos);
- if(this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates
- VoxelShape voxelshape = oldState.getCollisionShape(this, pos);
- VoxelShape voxelshape1 = newState.getCollisionShape(this, pos);
+ if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) {
+ List<PathNavigation> list = new ObjectArrayList();
+ Iterator iterator = this.navigatingMobs.iterator();
- if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) {
- List<PathNavigation> list = new ObjectArrayList();
- Iterator iterator = this.navigatingMobs.iterator();
+ while (iterator.hasNext()) {
+ // CraftBukkit start - fix SPIGOT-6362
+ Mob entityinsentient;
+ try {
+ entityinsentient = (Mob) iterator.next();
+ } catch (java.util.ConcurrentModificationException ex) {
+ // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register
+ // In this case we just run the update again across all the iterators as the chunk will then be loaded
+ // As this is a relative edge case it is much faster than copying navigators (on either read or write)
+ this.sendBlockUpdated(pos, oldState, newState, flags);
+ return;
+ }
+ // CraftBukkit end
+ PathNavigation navigationabstract = entityinsentient.getNavigation();
- while (iterator.hasNext()) {
- // CraftBukkit start - fix SPIGOT-6362
- Mob entityinsentient;
- try {
- entityinsentient = (Mob) iterator.next();
- } catch (java.util.ConcurrentModificationException ex) {
- // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register
- // In this case we just run the update again across all the iterators as the chunk will then be loaded
- // As this is a relative edge case it is much faster than copying navigators (on either read or write)
- this.sendBlockUpdated(pos, oldState, newState, flags);
- return;
- }
- // CraftBukkit end
- PathNavigation navigationabstract = entityinsentient.getNavigation();
+ if (navigationabstract.shouldRecomputePath(pos)) {
+ list.add(navigationabstract);
+ }
+ }
- if (navigationabstract.shouldRecomputePath(pos)) {
- list.add(navigationabstract);
- }
- }
+ try {
+ this.isUpdatingNavigations = true;
+ iterator = list.iterator();
- try {
- this.isUpdatingNavigations = true;
- iterator = list.iterator();
+ while (iterator.hasNext()) {
+ PathNavigation navigationabstract1 = (PathNavigation) iterator.next();
- while (iterator.hasNext()) {
- PathNavigation navigationabstract1 = (PathNavigation) iterator.next();
+ navigationabstract1.recomputePath();
+ }
+ } finally {
+ this.isUpdatingNavigations = false;
+ }
- navigationabstract1.recomputePath();
}
- } finally {
- this.isUpdatingNavigations = false;
- }
-
+ } // Paper
}
- } // Paper
}
@Override
@@ -1777,10 +1669,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
private void runBlockEvents() {
this.blockEventsToReschedule.clear();
-
- while (!this.blockEvents.isEmpty()) {
- BlockEventData blockactiondata = (BlockEventData) this.blockEvents.removeFirst();
-
+ BlockEventData blockactiondata;
+ while ((blockactiondata = (BlockEventData) this.blockEvents.pollFirst())!=null) {
if (this.shouldTickBlocksAt(blockactiondata.pos())) {
if (this.doBlockEvent(blockactiondata)) {
this.server.getPlayerList().broadcast((Player) null, (double) blockactiondata.pos().getX(), (double) blockactiondata.pos().getY(), (double) blockactiondata.pos().getZ(), 64.0D, this.dimension(), new ClientboundBlockEventPacket(blockactiondata.pos(), blockactiondata.block(), blockactiondata.paramA(), blockactiondata.paramB()));
diff --git a/src/main/java/net/minecraft/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/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..0eadacb873658a0c7bd9ab24f191bc75eaebcaca 100644
--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
+++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
@@ -3,11 +3,15 @@ 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.concurrent.locks.StampedLock;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import net.minecraft.util.profiling.metrics.MetricCategory;
@@ -19,7 +23,8 @@ 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 final StampedLock lock = new StampedLock();
private int blockingCount;
protected BlockableEventLoop(String name) {
@@ -117,13 +122,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 8f3f7a4c2429dd3c9060a1d2f412e41a5448bf4c..4216b4bba7c601660b7c39733f626f95d9b20507 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -24,6 +24,8 @@ import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.annotation.Nullable;
+
+import it.unimi.dsi.fastutil.objects.Object2DoubleMaps;
import net.minecraft.BlockUtil;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
@@ -164,76 +166,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
@@ -580,14 +513,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
this.nextStep = 1.0F;
this.random = SHARED_RANDOM; // Paper
this.remainingFireTicks = -this.getFireImmuneTicks();
- this.fluidHeight = new Object2DoubleArrayMap(2);
- this.fluidOnEyes = new HashSet();
+ this.fluidHeight = Object2DoubleMaps.synchronize(new Object2DoubleArrayMap(2));
+ this.fluidOnEyes = Sets.newConcurrentHashSet();
this.firstTick = true;
this.levelCallback = EntityInLevelCallback.NULL;
this.packetPositionCodec = new VecDeltaCodec();
this.uuid = Mth.createInsecureUUID(this.random);
this.stringUUID = this.uuid.toString();
- this.tags = Sets.newHashSet();
+ this.tags = Sets.newConcurrentHashSet();
this.pistonDeltas = new double[]{0.0D, 0.0D, 0.0D};
this.feetBlockState = null;
this.type = type;
@@ -4434,6 +4367,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
// Paper start
this.setPosRaw(x, y, z, false);
}
+
public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
// Paper start - block invalid positions
if (!checkPosition(this, x, y, z)) {
@@ -4441,12 +4375,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 +4490,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..c72920a17178059a29d21e96aeef398f6e0bbbdc 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -17,6 +17,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import net.minecraft.BlockUtil;
@@ -181,7 +182,7 @@ public abstract class LivingEntity extends Entity {
public static final float EXTRA_RENDER_CULLING_SIZE_WITH_BIG_HAT = 0.5F;
private final AttributeMap attributes;
public CombatTracker combatTracker = new CombatTracker(this);
- public final Map<MobEffect, MobEffectInstance> activeEffects = Maps.newHashMap();
+ public final Map<MobEffect, MobEffectInstance> activeEffects = Maps.newConcurrentMap();
private final NonNullList<ItemStack> lastHandItemStacks;
private final NonNullList<ItemStack> lastArmorItemStacks;
public boolean swinging;
@@ -257,7 +258,7 @@ public abstract class LivingEntity extends Entity {
// CraftBukkit start
public int expToDrop;
public boolean forceDrops;
- public ArrayList<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
+ public List<org.bukkit.inventory.ItemStack> drops = new CopyOnWriteArrayList<>();
public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes;
public boolean collides = true;
public Set<UUID> collidableExemptions = new HashSet<>();
@@ -875,7 +876,7 @@ public abstract class LivingEntity extends Entity {
// CraftBukkit start
private boolean isTickingEffects = false;
- private List<ProcessableEffect> effectsToProcess = Lists.newArrayList();
+ private List<ProcessableEffect> effectsToProcess = Lists.newCopyOnWriteArrayList();
private static class ProcessableEffect {
@@ -1779,7 +1780,7 @@ public abstract class LivingEntity extends Entity {
}
}); // Paper end
this.postDeathDropItems(deathEvent); // Paper
- this.drops = new ArrayList<>();
+ this.drops = new CopyOnWriteArrayList<>();
// CraftBukkit end
// this.dropInventory();// CraftBukkit - moved up
@@ -1963,6 +1964,10 @@ public abstract class LivingEntity extends Entity {
BlockPos blockposition = this.blockPosition();
BlockState iblockdata = this.getFeetBlockState();
+ if (iblockdata == null){
+ return false;
+ }
+
if (iblockdata.is(BlockTags.CLIMBABLE)) {
this.lastClimbablePos = Optional.of(blockposition);
return true;
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java b/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java
index d3827215ef19f6e1e63f846d91ed00525a318c7a..71e44f4aa64b29610f424ea91a9b54b56a155736 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
@@ -9,6 +9,8 @@ import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
+
+import net.himeki.mcmtfabric.parallelised.ConcurrentDoublyLinkedList;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
@@ -40,7 +42,7 @@ public class LongJumpToRandomPos<E extends Mob> extends Behavior<E> {
protected final int maxLongJumpHeight;
protected final int maxLongJumpWidth;
protected final float maxJumpVelocity;
- protected List<LongJumpToRandomPos.PossibleJump> jumpCandidates = Lists.newArrayList();
+ protected List<LongJumpToRandomPos.PossibleJump> jumpCandidates = Lists.newCopyOnWriteArrayList();
protected Optional<Vec3> initialPosition = Optional.empty();
@Nullable
protected Vec3 chosenJump;
@@ -103,7 +105,7 @@ public class LongJumpToRandomPos<E extends Mob> extends Behavior<E> {
return !blockPos2.equals(blockPos);
}).map((blockPos2) -> {
return new LongJumpToRandomPos.PossibleJump(blockPos2.immutable(), Mth.ceil(blockPos.distSqr(blockPos2)));
- }).collect(Collectors.toCollection(Lists::newArrayList));
+ }).collect(Collectors.toCollection(Lists::newCopyOnWriteArrayList));
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java
index fe3ab3d388f0481fb0db06b7f730f868dbf8e8a5..ac006bacbe8715e5c272c69afd1edab45a6511e8 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java
@@ -25,7 +25,7 @@ public class ShufflingList<U> implements Iterable<U> {
public ShufflingList(boolean isUnsafe) {
this.isUnsafe = isUnsafe;
// Paper end
- this.entries = Lists.newArrayList();
+ this.entries = Lists.newCopyOnWriteArrayList();
}
private ShufflingList(List<ShufflingList.WeightedEntry<U>> list) {
@@ -35,7 +35,7 @@ public class ShufflingList<U> implements Iterable<U> {
private ShufflingList(List<ShufflingList.WeightedEntry<U>> list, boolean isUnsafe) {
this.isUnsafe = isUnsafe;
// Paper end
- this.entries = Lists.newArrayList(list);
+ this.entries = Lists.newCopyOnWriteArrayList(list);
}
public static <U> Codec<ShufflingList<U>> codec(Codec<U> codec) {
@@ -44,12 +44,12 @@ public class ShufflingList<U> implements Iterable<U> {
});
}
- public ShufflingList<U> add(U data, int weight) {
+ public synchronized ShufflingList<U> add(U data, int weight) {
this.entries.add(new ShufflingList.WeightedEntry<>(data, weight));
return this;
}
- public ShufflingList<U> shuffle() {
+ public synchronized ShufflingList<U> shuffle() {
// Paper start - make concurrent safe, work off a clone of the list
List<ShufflingList.WeightedEntry<U>> list = this.isUnsafe ? Lists.newArrayList(this.entries) : this.entries;
list.forEach(entry -> entry.setRandom(this.random.nextFloat()));
@@ -58,17 +58,17 @@ public class ShufflingList<U> implements Iterable<U> {
// Paper end
}
- public Stream<U> stream() {
+ public synchronized Stream<U> stream() {
return this.entries.stream().map(ShufflingList.WeightedEntry::getData);
}
@Override
- public Iterator<U> iterator() {
+ public synchronized Iterator<U> iterator() {
return Iterators.transform(this.entries.iterator(), ShufflingList.WeightedEntry::getData);
}
@Override
- public String toString() {
+ public synchronized String toString() {
return "ShufflingList[" + this.entries + "]";
}
@@ -90,16 +90,16 @@ public class ShufflingList<U> implements Iterable<U> {
this.randWeight = -Math.pow((double)random, (double)(1.0F / (float)this.weight));
}
- public T getData() {
+ public synchronized T getData() {
return this.data;
}
- public int getWeight() {
+ public synchronized int getWeight() {
return this.weight;
}
@Override
- public String toString() {
+ public synchronized String toString() {
return this.weight + ":" + this.data;
}
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
index 02978315bc2b828cc603ce7478408f3f82c249c2..fc26edc5082f701e6450ca9abf78423840cd773c 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -3,11 +3,8 @@ package net.minecraft.world.entity.ai.goal;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets;
import com.mojang.logging.LogUtils;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
+
+import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -27,8 +24,8 @@ public class GoalSelector {
return false;
}
};
- private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
- private final Set<WrappedGoal> availableGoals = Sets.newLinkedHashSet();
+ private final Map<Goal.Flag, WrappedGoal> lockedFlags = Collections.synchronizedMap(new EnumMap<>(Goal.Flag.class));
+ private final Set<WrappedGoal> availableGoals = Sets.newConcurrentHashSet();
private final Supplier<ProfilerFiller> profiler;
private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
@@ -114,14 +111,7 @@ public class GoalSelector {
}
}
- Iterator<Map.Entry<Goal.Flag, WrappedGoal>> iterator = this.lockedFlags.entrySet().iterator();
-
- while(iterator.hasNext()) {
- Map.Entry<Goal.Flag, WrappedGoal> entry = iterator.next();
- if (!entry.getValue().isRunning()) {
- iterator.remove();
- }
- }
+ this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning());
//profilerFiller.pop(); // Purpur
//profilerFiller.push("goalUpdate"); // Purpur
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
index 8db20db72cd51046213625fac46c35854c59ec5d..4d40526cc90c19ff5a1569c8d6d828a0d0b73ccb 100644
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
@@ -3,6 +3,7 @@ package net.minecraft.world.entity.ai.sensing;
import com.google.common.collect.ImmutableSet;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.longs.Long2LongMap;
+import it.unimi.dsi.fastutil.longs.Long2LongMaps;
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import java.util.Optional;
import java.util.Set;
@@ -23,7 +24,7 @@ public class NearestBedSensor extends Sensor<Mob> {
private static final int CACHE_TIMEOUT = 40;
private static final int BATCH_SIZE = 5;
private static final int RATE = 20;
- private final Long2LongMap batchCache = new Long2LongOpenHashMap();
+ private final Long2LongMap batchCache = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
private int triedCount;
private long lastUpdate;
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java
index 9babe636176da3c40598eb5bdac0919a1704eaa0..58c6b1f67aedf5ab2167fd070604fc0d8f710435 100644
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensing.java
@@ -2,13 +2,14 @@ package net.minecraft.world.entity.ai.sensing;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
+import it.unimi.dsi.fastutil.ints.IntSets;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob;
public class Sensing {
private final Mob mob;
- private final IntSet seen = new IntOpenHashSet();
- private final IntSet unseen = new IntOpenHashSet();
+ private final IntSet seen = IntSets.synchronize(new IntOpenHashSet());
+ private final IntSet unseen = IntSets.synchronize(new IntOpenHashSet());
public Sensing(Mob owner) {
this.mob = owner;
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..3e8b68b4390a6086b1b1983fe6f8b545c2847ef8 100644
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
@@ -4,6 +4,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nullable;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
@@ -239,21 +241,24 @@ public class ItemEntity extends Entity {
this.setDeltaMovement(vec3d.x * 0.949999988079071D, vec3d.y + (double) (vec3d.y < 0.05999999865889549D ? 5.0E-4F : 0.0F), vec3d.z * 0.949999988079071D);
}
+ private final Lock mergeLock = new ReentrantLock();
+
private void mergeWithNeighbours() {
- if (this.isMergable()) {
- // Spigot start
- double radius = level.spigotConfig.itemMerge;
- List<ItemEntity> list = this.level.getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, radius - 0.5D, radius), (entityitem) -> {
- // Spigot end
- return entityitem != this && entityitem.isMergable();
- });
- Iterator iterator = list.iterator();
-
- while (iterator.hasNext()) {
- ItemEntity entityitem = (ItemEntity) iterator.next();
-
- if (entityitem.isMergable()) {
- // Paper Start - Fix items merging through walls
+ if (!this.mergeLock.tryLock()){
+ return;
+ }
+ try {
+ if (this.isMergable()) {
+ // Spigot start
+ double radius = level.spigotConfig.itemMerge;
+ List<ItemEntity> list = this.level.getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(radius, radius - 0.5D, radius), (entityitem) -> {
+ // Spigot end
+ return entityitem != this && entityitem.isMergable();
+ });
+
+ for (ItemEntity entityitem : list) {
+ if (entityitem.isMergable()) {
+ // Paper Start - Fix items merging through walls
if (this.level.paperConfig().fixes.fixItemsMergingThroughWalls) {
// Pufferfish start - skip the allocations
/*
@@ -263,17 +268,19 @@ public class ItemEntity extends Entity {
if (rayTraceResult.getType() == net.minecraft.world.phys.HitResult.Type.BLOCK) continue;
*/
if (level.rayTraceDirect(this.position(), entityitem.position(), net.minecraft.world.phys.shapes.CollisionContext.of(this)) ==
- net.minecraft.world.phys.HitResult.Type.BLOCK) continue;
+ net.minecraft.world.phys.HitResult.Type.BLOCK) continue;
// Pufferfish end
}
- // Paper End
- this.tryToMerge(entityitem);
- if (this.isRemoved()) {
- break;
+ // Paper End
+ this.tryToMerge(entityitem);
+ if (this.isRemoved()) {
+ break;
+ }
}
}
}
-
+ }finally {
+ this.mergeLock.unlock();
}
}
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 8450a22b0fc6e8dc5cad0f61ac52a82b3cd3791e..c55f98fb2a6aade8e0a6f60248f4e29f66f0c193 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -248,7 +248,9 @@ public final class ItemStack {
}
private void updateEmptyCacheFlag() {
- if (this.emptyCacheFlag && this == ItemStack.EMPTY) throw new AssertionError("TRAP"); // CraftBukkit
+ if (this.emptyCacheFlag && this == ItemStack.EMPTY){
+ return;
+ }//throw new AssertionError("TRAP"); // CraftBukkit
this.emptyCacheFlag = false;
this.emptyCacheFlag = this.isEmpty();
}
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index c0d39afe5b80159ed9aaca4ddd4763d707882f2e..a4e031682329e127a61a9fa03a7383cd3e58d503 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -4,12 +4,15 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import it.unimi.dsi.fastutil.objects.ObjectList;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
+
+import it.unimi.dsi.fastutil.objects.ObjectLists;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
@@ -81,9 +84,9 @@ public class Explosion {
}
public Explosion(Level world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Explosion.BlockInteraction destructionType) {
- this.random = RandomSource.create();
- this.toBlow = new ObjectArrayList();
- this.hitPlayers = Maps.newHashMap();
+ this.random = RandomSource.createThreadSafe();
+ this.toBlow = new ObjectArrayList<>();
+ this.hitPlayers = Maps.newConcurrentMap();
this.level = world;
this.source = entity;
this.radius = (float) Math.max(power, 0.0); // CraftBukkit - clamp bad values
@@ -396,14 +399,10 @@ public class Explosion {
}
if (this.fire) {
- ObjectListIterator objectlistiterator1 = this.toBlow.iterator();
-
- while (objectlistiterator1.hasNext()) {
- BlockPos blockposition2 = (BlockPos) objectlistiterator1.next();
-
+ for (BlockPos blockposition2 : this.toBlow) {
if (this.random.nextInt(3) == 0 && this.level.getBlockState(blockposition2).isAir() && this.level.getBlockState(blockposition2.below()).isSolidRender(this.level, blockposition2.below())) {
// CraftBukkit start - Ignition by explosion
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level, blockposition2.getX(), blockposition2.getY(), blockposition2.getZ(), this).isCancelled()) {
+ if (!CraftEventFactory.callBlockIgniteEvent(this.level, blockposition2.getX(), blockposition2.getY(), blockposition2.getZ(), this).isCancelled()) {
this.level.setBlockAndUpdate(blockposition2, BaseFireBlock.getState(this.level, blockposition2));
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 958e0ee29915bddde2cb8ebfd578448b83e2b149..4a75c2895f4f5e3229be3c7b177445611a1e70b6 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -2,10 +2,12 @@ package net.minecraft.world.level;
import co.aikar.timings.Timing;
import co.aikar.timings.Timings;
+import co.earthme.hearse.concurrent.WorkerThread;
import com.destroystokyo.paper.event.server.ServerExceptionEvent;
import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.mojang.serialization.Codec;
import java.io.IOException;
import java.util.Iterator;
@@ -178,7 +180,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
- public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = Maps.newConcurrentMap(); // Paper - Optimize explosions
public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
// Paper start - fix and optimise world upgrading
@@ -1116,7 +1118,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
}
// Paper end
// CraftBukkit end
- return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !io.papermc.paper.util.TickThread.isTickThread() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system
+ return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !io.papermc.paper.util.TickThread.isTickThread() && !WorkerThread.isWorker() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system
}
public void setBlockEntity(BlockEntity blockEntity) {
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
index e254b2d04e4fc1dc76c26f61ea38aeb27755143f..948abd93c64a5b3679f3552945d7a9a2edaf7c3f 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -17,6 +17,9 @@ import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
+
+import it.unimi.dsi.fastutil.shorts.ShortLists;
+import net.himeki.mcmtfabric.parallelised.fastutil.ConcurrentShortHashSet;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
@@ -384,7 +387,7 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom
public static ShortList getOrCreateOffsetList(ShortList[] lists, int index) {
if (lists[index] == null) {
- lists[index] = new ShortArrayList();
+ lists[index] = ShortLists.synchronize(new ShortArrayList());
}
return lists[index];
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..f1aae5aa6d2951e21e5e0f84fc87117d41876695 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -88,7 +88,7 @@ public class LevelChunk extends ChunkAccess {
private Supplier<ChunkHolder.FullChunkStatus> fullStatus;
@Nullable
private LevelChunk.PostLoadProcessor postLoad;
- private final Int2ObjectMap<GameEventListenerRegistry> gameEventListenerRegistrySections;
+ private final Map<Integer,GameEventListenerRegistry> gameEventListenerRegistrySections;
private final LevelChunkTicks<Block> blockTicks;
private final LevelChunkTicks<Fluid> fluidTicks;
@@ -114,10 +114,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 = Maps.newConcurrentMap();
Heightmap.Types[] aheightmap_type = Heightmap.Types.values();
int j = aheightmap_type.length;
@@ -1075,10 +1075,8 @@ public class LevelChunk extends ChunkAccess {
for (int i = 0; i < this.postProcessing.length; ++i) {
if (this.postProcessing[i] != null) {
- ShortListIterator shortlistiterator = this.postProcessing[i].iterator();
- while (shortlistiterator.hasNext()) {
- Short oshort = (Short) shortlistiterator.next();
+ for (Short oshort : this.postProcessing[i]) {
BlockPos blockposition = ProtoChunk.unpackOffsetCoordinates(oshort, this.getSectionYFromSectionIndex(i), chunkcoordintpair);
BlockState iblockdata = this.getBlockState(blockposition);
FluidState fluid = iblockdata.getFluidState();
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..2a14b665437336aa32ca14fb2137d5bb400e2e42 100644
--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
@@ -1,49 +1,31 @@
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 com.google.common.collect.Lists;
import net.minecraft.world.entity.Entity;
+import java.util.List;
+import java.util.function.Consumer;
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 List<Entity> entities = Lists.newCopyOnWriteArrayList();
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
+ this.entities.add(entity);
}
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
+ this.entities.remove(entity);
}
public boolean contains(Entity entity) {
- return this.entities.contains(entity); // Paper - replace with better logic, do not delay removals/additions
+ return this.entities.contains(entity);
}
public void forEach(Consumer<Entity> action) {
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/gameevent/EuclideanGameEventListenerRegistry.java b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
index 878a42695ecedf0c3f2e6310e3ce44c6b6c36858..b61ed4d03848f86ca5e93b0374bbf4ca05369ad2 100644
--- a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
+++ b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java
@@ -2,18 +2,21 @@ package net.minecraft.world.level.gameevent;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
+
+import java.util.*;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import it.unimi.dsi.fastutil.objects.ObjectList;
+import it.unimi.dsi.fastutil.objects.ObjectLists;
+import net.himeki.mcmtfabric.parallelised.ConcurrentDoublyLinkedList;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.phys.Vec3;
public class EuclideanGameEventListenerRegistry implements GameEventListenerRegistry {
- private final List<GameEventListener> listeners = 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..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/pathfinder/BinaryHeap.java b/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
index 27b9cefc172b391824ead382a712b8b9b1ddfe45..4b65331a9192b7ac75141183493126ee730e697e 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
@@ -4,9 +4,9 @@ public class BinaryHeap {
private Node[] heap = new Node[128];
private int size;
- public Node insert(Node node) {
+ public synchronized Node insert(Node node) {
if (node.heapIdx >= 0) {
- throw new IllegalStateException("OW KNOWS!");
+ return node;
} else {
if (this.size == this.heap.length) {
Node[] nodes = new Node[this.size << 1];
@@ -21,15 +21,15 @@ public class BinaryHeap {
}
}
- public void clear() {
+ public synchronized void clear() {
this.size = 0;
}
- public Node peek() {
+ public synchronized Node peek() {
return this.heap[0];
}
- public Node pop() {
+ public synchronized Node pop() {
Node node = this.heap[0];
this.heap[0] = this.heap[--this.size];
this.heap[this.size] = null;
@@ -41,7 +41,7 @@ public class BinaryHeap {
return node;
}
- public void remove(Node node) {
+ public synchronized void remove(Node node) {
this.heap[node.heapIdx] = this.heap[--this.size];
this.heap[this.size] = null;
if (this.size > node.heapIdx) {
@@ -55,7 +55,7 @@ public class BinaryHeap {
node.heapIdx = -1;
}
- public void changeCost(Node node, float weight) {
+ public synchronized void changeCost(Node node, float weight) {
float f = node.f;
node.f = weight;
if (weight < f) {
@@ -66,11 +66,14 @@ public class BinaryHeap {
}
- public int size() {
+ public synchronized int size() {
return this.size;
}
private void upHeap(int index) {
+ if(index == -1){
+ return;
+ }
Node node = this.heap[index];
int i;
@@ -90,6 +93,9 @@ public class BinaryHeap {
}
private void downHeap(int index) {
+ if(index == -1){
+ return;
+ }
Node node = this.heap[index];
float f = node.f;
@@ -135,11 +141,11 @@ public class BinaryHeap {
node.heapIdx = index;
}
- public boolean isEmpty() {
+ public synchronized boolean isEmpty() {
return this.size == 0;
}
- public Node[] getHeap() {
+ public synchronized Node[] getHeap() {
Node[] nodes = new Node[this.size()];
System.arraycopy(this.heap, 0, nodes, 0, this.size());
return nodes;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java
index b0bae04ab5a93dd4cf1eeeb02bed1e508e1f2913..d427735eff0056c171591709829d0bb76f7bb6f3 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java
@@ -1,6 +1,7 @@
package net.minecraft.world.level.pathfinder;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.util.EnumSet;
import java.util.List;
@@ -15,7 +16,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
public class FlyNodeEvaluator extends WalkNodeEvaluator {
- private final Long2ObjectMap<BlockPathTypes> pathTypeByPosCache = new Long2ObjectOpenHashMap<>();
+ private final Long2ObjectMap<BlockPathTypes> pathTypeByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
private static final float SMALL_MOB_INFLATED_START_NODE_BOUNDING_BOX = 1.5F;
private static final int MAX_START_NODE_CANDIDATES = 10;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
index a8a2594b8f5b3ebf6a1f918c7d822ad35b051b17..c614bcfc2bbbbccc7c4aac9389d4780478e739d2 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
@@ -1,6 +1,7 @@
package net.minecraft.world.level.pathfinder;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
@@ -11,7 +12,7 @@ import net.minecraft.world.level.PathNavigationRegion;
public abstract class NodeEvaluator {
protected PathNavigationRegion level;
protected Mob mob;
- protected final Int2ObjectMap<Node> nodes = new Int2ObjectOpenHashMap<>();
+ protected final Int2ObjectMap<Node> nodes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
protected int entityWidth;
protected int entityHeight;
protected int entityDepth;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
index a8af51a25b0f99c3a64d9150fdfcd6b818aa7581..cd2592552339a79361d2a4e7936731330e15f6fa 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
@@ -31,7 +31,7 @@ public class PathFinder {
}
@Nullable
- public Path findPath(PathNavigationRegion world, Mob mob, Set<BlockPos> positions, float followRange, int distance, float rangeMultiplier) {
+ public synchronized Path findPath(PathNavigationRegion world, Mob mob, Set<BlockPos> positions, float followRange, int distance, float rangeMultiplier) {
this.openSet.clear();
this.nodeEvaluator.prepare(world, mob);
Node node = this.nodeEvaluator.getStart();
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
index 6084631b5b502279b84f190dc62fc76b770e368e..f526adbd31e65fc74af48f6137d293a7a7ceafbb 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
@@ -2,6 +2,7 @@ package net.minecraft.world.level.pathfinder;
import com.google.common.collect.Maps;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.util.Map;
import javax.annotation.Nullable;
@@ -17,7 +18,7 @@ import net.minecraft.world.level.material.FluidState;
public class SwimNodeEvaluator extends NodeEvaluator {
private final boolean allowBreaching;
- private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = new Long2ObjectOpenHashMap<>();
+ private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
public SwimNodeEvaluator(boolean canJumpOutOfWater) {
this.allowBreaching = canJumpOutOfWater;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
index 894881018c659d874f28f5744f0b8247cfecb1c1..ae06f7ef9c4b8147508984f8b46176de46171285 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
@@ -1,8 +1,10 @@
package net.minecraft.world.level.pathfinder;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
+import it.unimi.dsi.fastutil.objects.Object2BooleanMaps;
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
import java.util.EnumSet;
import javax.annotation.Nullable;
@@ -33,8 +35,8 @@ public class WalkNodeEvaluator extends NodeEvaluator {
public static final double SPACE_BETWEEN_WALL_POSTS = 0.5D;
private static final double DEFAULT_MOB_JUMP_HEIGHT = 1.125D;
protected float oldWaterCost;
- private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = new Long2ObjectOpenHashMap<>();
- private final Object2BooleanMap<AABB> collisionCache = new Object2BooleanOpenHashMap<>();
+ private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
+ private final Object2BooleanMap<AABB> collisionCache = Object2BooleanMaps.synchronize(new Object2BooleanOpenHashMap<>());
@Override
public void prepare(PathNavigationRegion cachedWorld, Mob entity) {
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..a1ff442357dfea868c319fd3c10ae28e6fb81956 100644
--- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
+++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
@@ -3,7 +3,11 @@ package net.minecraft.world.level.redstone;
import com.mojang.logging.LogUtils;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Deque;
import java.util.List;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.StampedLock;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -16,8 +20,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 +30,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));
}
@@ -62,20 +66,18 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
if (!bl) {
this.runUpdates();
}
-
}
private void runUpdates() {
try {
- while(!this.stack.isEmpty() || !this.addedThisLayer.isEmpty()) {
- for(int i = this.addedThisLayer.size() - 1; i >= 0; --i) {
+ 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()) {
+ while (this.addedThisLayer.isEmpty()) {
if (!neighborUpdates.runNext(this.level)) {
this.stack.pop();
break;
@@ -87,7 +89,6 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
this.addedThisLayer.clear();
this.count = 0;
}
-
}
static record FullNeighborUpdate(BlockState state, BlockPos pos, Block block, BlockPos neighborPos, boolean movedByPiston) implements CollectingNeighborUpdater.NeighborUpdates {
diff --git a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java
index ac807277a6b26d140ea9873d17c7aa4fb5fe37b2..4c75f50ab0184637b72e08936ff8808ad6c6fb5f 100644
--- a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java
+++ b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java
@@ -13,6 +13,8 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.annotation.Nullable;
+
+import it.unimi.dsi.fastutil.objects.ObjectSets;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.level.ChunkPos;
@@ -21,7 +23,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
private final Queue<ScheduledTick<T>> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER);
@Nullable
private List<SavedTick<T>> pendingTicks;
- private final Set<ScheduledTick<?>> ticksPerPosition = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
+ private final Set<ScheduledTick<?>> ticksPerPosition = ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH));
@Nullable
private BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> onTickAdded;
@@ -29,11 +31,11 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
private boolean dirty;
private long lastSaved = Long.MIN_VALUE;
- public boolean isDirty(final long tick) {
+ public synchronized boolean isDirty(final long tick) {
return this.dirty || (!this.tickQueue.isEmpty() && tick != this.lastSaved);
}
- public void clearDirty() {
+ public synchronized void clearDirty() {
this.dirty = false;
}
// Paper end - add dirty flag
@@ -50,17 +52,17 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
- public void setOnTickAdded(@Nullable BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> tickConsumer) {
+ public synchronized void setOnTickAdded(@Nullable BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> tickConsumer) {
this.onTickAdded = tickConsumer;
}
@Nullable
- public ScheduledTick<T> peek() {
+ public synchronized ScheduledTick<T> peek() {
return this.tickQueue.peek();
}
@Nullable
- public ScheduledTick<T> poll() {
+ public synchronized ScheduledTick<T> poll() {
ScheduledTick<T> scheduledTick = this.tickQueue.poll();
if (scheduledTick != null) {
this.dirty = true; // Paper - add dirty flag
@@ -71,7 +73,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
@Override
- public void schedule(ScheduledTick<T> orderedTick) {
+ public synchronized void schedule(ScheduledTick<T> orderedTick) {
if (this.ticksPerPosition.add(orderedTick)) {
this.dirty = true; // Paper - add dirty flag
this.scheduleUnchecked(orderedTick);
@@ -88,11 +90,11 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
@Override
- public boolean hasScheduledTick(BlockPos pos, T type) {
+ public synchronized boolean hasScheduledTick(BlockPos pos, T type) {
return this.ticksPerPosition.contains(ScheduledTick.probe(type, pos));
}
- public void removeIf(Predicate<ScheduledTick<T>> predicate) {
+ public synchronized void removeIf(Predicate<ScheduledTick<T>> predicate) {
Iterator<ScheduledTick<T>> iterator = this.tickQueue.iterator();
while(iterator.hasNext()) {
@@ -105,17 +107,17 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
- public Stream<ScheduledTick<T>> getAll() {
+ public synchronized Stream<ScheduledTick<T>> getAll() {
return this.tickQueue.stream();
}
@Override
- public int count() {
+ public synchronized int count() {
return this.tickQueue.size() + (this.pendingTicks != null ? this.pendingTicks.size() : 0);
}
@Override
- public ListTag save(long l, Function<T, String> function) {
+ public synchronized ListTag save(long l, Function<T, String> function) {
this.lastSaved = l; // Paper - add dirty system to level ticks
ListTag listTag = new ListTag();
if (this.pendingTicks != null) {
@@ -131,7 +133,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
return listTag;
}
- public void unpack(long time) {
+ public synchronized void unpack(long time) {
if (this.pendingTicks != null) {
// Paper start - add dirty system to level chunk ticks
if (this.tickQueue.isEmpty()) {
diff --git a/src/main/java/net/minecraft/world/ticks/LevelTicks.java b/src/main/java/net/minecraft/world/ticks/LevelTicks.java
index 5dea8414964e0d2d1fb15a6baa27227e9722bfc7..2203adc2a68e7fb253e353098fd6ddad521e3a32 100644
--- a/src/main/java/net/minecraft/world/ticks/LevelTicks.java
+++ b/src/main/java/net/minecraft/world/ticks/LevelTicks.java
@@ -1,24 +1,9 @@
package net.minecraft.world.ticks;
-import it.unimi.dsi.fastutil.longs.Long2LongMap;
-import it.unimi.dsi.fastutil.longs.Long2LongMaps;
-import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
-import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.longs.*;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.LongSummaryStatistics;
-import java.util.PriorityQueue;
-import java.util.Queue;
-import java.util.Set;
-import java.util.function.BiConsumer;
-import java.util.function.LongPredicate;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
+import it.unimi.dsi.fastutil.objects.ObjectSets;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
@@ -26,31 +11,36 @@ import net.minecraft.core.Vec3i;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
+import java.util.*;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.BiConsumer;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
public class LevelTicks<T> implements LevelTickAccess<T> {
private static final Comparator<LevelChunkTicks<?>> CONTAINER_DRAIN_ORDER = (a, b) -> {
return ScheduledTick.INTRA_TICK_DRAIN_ORDER.compare(a.peek(), b.peek());
};
private final LongPredicate tickCheck;
- private final Supplier<ProfilerFiller> profiler;
- private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = new Long2ObjectOpenHashMap<>();
+ private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
private final Long2LongMap nextTickForContainer = Util.make(new Long2LongOpenHashMap(), (map) -> {
map.defaultReturnValue(Long.MAX_VALUE);
});
private final Queue<LevelChunkTicks<T>> containersToTick = new PriorityQueue<>(CONTAINER_DRAIN_ORDER);
- private final Queue<ScheduledTick<T>> toRunThisTick = new ArrayDeque<>();
- private final List<ScheduledTick<T>> alreadyRunThisTick = new ArrayList<>();
- private final Set<ScheduledTick<?>> toRunThisTickSet = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
+ private final Queue<ScheduledTick<T>> toRunThisTick = new ConcurrentLinkedDeque<>();
+ private final List<ScheduledTick<T>> alreadyRunThisTick = new CopyOnWriteArrayList<>();
+ private final Set<ScheduledTick<?>> toRunThisTickSet = ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH));
+
private final BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> chunkScheduleUpdater = (chunkTickScheduler, tick) -> {
if (tick.equals(chunkTickScheduler.peek())) {
this.updateContainerScheduling(tick);
}
-
};
public LevelTicks(LongPredicate tickingFutureReadyPredicate, Supplier<ProfilerFiller> profilerGetter) {
this.tickCheck = tickingFutureReadyPredicate;
- this.profiler = profilerGetter;
}
public void addContainer(ChunkPos pos, LevelChunkTicks<T> scheduler) {
@@ -123,7 +113,9 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
entry.setValue(scheduledTick.triggerTick());
} else if (this.tickCheck.test(l)) {
objectIterator.remove();
- this.containersToTick.add(levelChunkTicks);
+ synchronized (this.containersToTick){
+ this.containersToTick.add(levelChunkTicks);
+ }
}
}
}
@@ -133,27 +125,29 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
private void drainContainers(long time, int maxTicks) {
LevelChunkTicks<T> levelChunkTicks;
- while(this.canScheduleMoreTicks(maxTicks) && (levelChunkTicks = this.containersToTick.poll()) != null) {
- ScheduledTick<T> scheduledTick = levelChunkTicks.poll();
- this.scheduleForThisTick(scheduledTick);
- this.drainFromCurrentContainer(this.containersToTick, levelChunkTicks, time, maxTicks);
- ScheduledTick<T> scheduledTick2 = levelChunkTicks.peek();
- if (scheduledTick2 != null) {
- if (scheduledTick2.triggerTick() <= time && this.canScheduleMoreTicks(maxTicks)) {
- this.containersToTick.add(levelChunkTicks);
- } else {
- this.updateContainerScheduling(scheduledTick2);
+ synchronized (this.containersToTick){
+ while(this.canScheduleMoreTicks(maxTicks) && (levelChunkTicks = this.containersToTick.poll()) != null) {
+ ScheduledTick<T> scheduledTick = levelChunkTicks.poll();
+ this.scheduleForThisTick(scheduledTick);
+ this.drainFromCurrentContainer(this.containersToTick, levelChunkTicks, time, maxTicks);
+ ScheduledTick<T> scheduledTick2 = levelChunkTicks.peek();
+ if (scheduledTick2 != null) {
+ if (scheduledTick2.triggerTick() <= time && this.canScheduleMoreTicks(maxTicks)) {
+ this.containersToTick.add(levelChunkTicks);
+ } else {
+ this.updateContainerScheduling(scheduledTick2);
+ }
}
}
}
-
}
private void rescheduleLeftoverContainers() {
- for(LevelChunkTicks<T> levelChunkTicks : this.containersToTick) {
- this.updateContainerScheduling(levelChunkTicks.peek());
+ synchronized (this.containersToTick){
+ for(LevelChunkTicks<T> levelChunkTicks : this.containersToTick) {
+ this.updateContainerScheduling(levelChunkTicks.peek());
+ }
}
-
}
private void updateContainerScheduling(ScheduledTick<T> tick) {
@@ -201,7 +195,9 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
private void cleanupAfterTick() {
this.toRunThisTick.clear();
- this.containersToTick.clear();
+ synchronized (this.containersToTick){
+ this.containersToTick.clear();
+ }
this.alreadyRunThisTick.clear();
this.toRunThisTickSet.clear();
}