From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: wangxyper Date: Sun, 8 Jan 2023 21:48:49 +0800 Subject: [PATCH] Hearse: MC code changes Original license: MIT Original project: https://github.com/NaturalCodeClub/HearseRewrite diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java index 24c677e80af652952263253409c050641e72e3b5..c6f9fb3efb92de0879eab6389fabd531bb4cfcb2 100644 --- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java +++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java @@ -1,7 +1,8 @@ package net.minecraft.network.protocol.game; -import it.unimi.dsi.fastutil.shorts.ShortIterator; import it.unimi.dsi.fastutil.shorts.ShortSet; +import java.util.ArrayList; +import java.util.List; import java.util.function.BiConsumer; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; @@ -22,14 +23,16 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet copy = new ArrayList<>(positions); + this.positions = new short[copy.size()]; + this.states = new BlockState[copy.size()]; + for (int i = 0; i < copy.size(); i++) { + this.positions[i] = copy.get(i); + } - this.positions = new short[i]; - this.states = new BlockState[i]; - int j = 0; - for (ShortIterator shortiterator = positions.iterator(); shortiterator.hasNext(); ++j) { - short short0 = (Short) shortiterator.next(); + for (int j = 0;j < this.positions.length;j++) { + short short0 = this.positions[j]; this.positions[j] = short0; this.states[j] = (section != null) ? section.getBlockState(SectionPos.sectionRelativeX(short0), SectionPos.sectionRelativeY(short0), SectionPos.sectionRelativeZ(short0)) : net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(); // CraftBukkit - SPIGOT-6076, Mojang bug when empty chunk section notified diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java index bc46479fd0622a90fd98ac88f92b2840a22a2d04..e642b4a83687d03e55feb340452d608c53ae7cce 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -2,19 +2,9 @@ package net.minecraft.server.level; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.shorts.ShortOpenHashSet; +import it.unimi.dsi.fastutil.shorts.ShortArraySet; import it.unimi.dsi.fastutil.shorts.ShortSet; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicReferenceArray; -import java.util.function.IntConsumer; -import java.util.function.IntSupplier; -import javax.annotation.Nullable; -import net.minecraft.Util; +import it.unimi.dsi.fastutil.shorts.ShortSets; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.network.protocol.Packet; @@ -29,15 +19,14 @@ import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.ImposterProtoChunk; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.*; import net.minecraft.world.level.lighting.LevelLightEngine; -// CraftBukkit start -import net.minecraft.server.MinecraftServer; +import javax.annotation.Nullable; +import java.util.BitSet; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.IntConsumer; +import java.util.function.IntSupplier; // CraftBukkit end public class ChunkHolder { @@ -233,7 +222,7 @@ public class ChunkHolder { if (i < 0 || i >= this.changedBlocksPerSection.length) return; // CraftBukkit - SPIGOT-6086, SPIGOT-6296 if (this.changedBlocksPerSection[i] == null) { this.hasChangedSections = true; this.addToBroadcastMap(); // Paper - optimise chunk tick iteration - this.changedBlocksPerSection[i] = new ShortOpenHashSet(); + this.changedBlocksPerSection[i] = ShortSets.synchronize(new ShortArraySet()); } this.changedBlocksPerSection[i].add(SectionPos.sectionRelativePos(pos)); diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java index beb7c22cb63021f26c06f91050361e1b25fcc72d..10c7d776ca0d959541d3110c75ceb45a340278ac 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -1,57 +1,25 @@ package net.minecraft.server.level; -import co.aikar.timings.Timing; // Paper import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.Iterables; -import com.google.common.collect.ComparisonChain; // Paper import com.google.common.collect.Lists; import com.google.common.collect.Queues; -import com.google.common.collect.Sets; import com.google.gson.JsonElement; import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.util.Either; import com.mojang.logging.LogUtils; import com.mojang.serialization.DataResult; import com.mojang.serialization.JsonOps; +import io.papermc.paper.util.MCUtil; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ByteMap; -import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2LongMap; -import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import it.unimi.dsi.fastutil.longs.LongSet; -import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +import it.unimi.dsi.fastutil.longs.*; import it.unimi.dsi.fastutil.objects.ObjectIterator; -import java.io.IOException; -import java.io.Writer; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Objects; -import java.util.Optional; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BooleanSupplier; -import java.util.function.Consumer; -import java.util.function.IntFunction; -import java.util.function.IntSupplier; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import javax.annotation.Nullable; +import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; +import it.unimi.dsi.fastutil.objects.ReferenceSet; +import it.unimi.dsi.fastutil.objects.ReferenceSets; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; @@ -63,36 +31,19 @@ import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket; -import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; -import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.network.protocol.game.DebugPackets; -import io.papermc.paper.util.MCUtil; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.network.ServerPlayerConnection; -import net.minecraft.util.CsvOutput; import net.minecraft.util.Mth; -import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.thread.BlockableEventLoop; -import net.minecraft.util.thread.ProcessorHandle; -import net.minecraft.util.thread.ProcessorMailbox; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.village.poi.PoiManager; import net.minecraft.world.entity.boss.EnderDragonPart; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.ImposterProtoChunk; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LightChunkGetter; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.*; import net.minecraft.world.level.chunk.storage.ChunkSerializer; import net.minecraft.world.level.chunk.storage.ChunkStorage; import net.minecraft.world.level.entity.ChunkStatusUpdateListener; @@ -101,19 +52,24 @@ import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.levelgen.RandomState; import net.minecraft.world.level.levelgen.blending.BlendingData; -import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; import net.minecraft.world.level.storage.DimensionDataStorage; import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.phys.Vec3; -import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableObject; -import org.slf4j.Logger; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; -import org.bukkit.entity.Player; -// CraftBukkit end +import org.slf4j.Logger; -import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.*; public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider { @@ -153,7 +109,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private final Queue unloadQueue; int viewDistance; public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper - public final ReferenceOpenHashSet needsChangeBroadcasting = new ReferenceOpenHashSet<>(); + public final ReferenceSet needsChangeBroadcasting = ReferenceSets.synchronize(new ReferenceOpenHashSet<>()); // Paper - rewrite chunk system // Paper start - optimise checkDespawn @@ -295,9 +251,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper - rewrite chunk system this.tickingGenerated = new AtomicInteger(); this.playerMap = new PlayerMap(); - this.entityMap = new Int2ObjectOpenHashMap(); - this.chunkTypeCache = new Long2ByteOpenHashMap(); - this.chunkSaveCooldowns = new Long2LongOpenHashMap(); + this.entityMap = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap()); + this.chunkTypeCache = Long2ByteMaps.synchronize(new Long2ByteOpenHashMap()); + this.chunkSaveCooldowns = Long2LongMaps.synchronize(new Long2LongOpenHashMap()); this.unloadQueue = Queues.newConcurrentLinkedQueue(); this.structureTemplateManager = structureTemplateManager; Path path = session.getDimensionPath(world.dimension()); diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java index 52cba8f68d274cce106304aef1249a95474d3238..a9ba8adc5f290f6e2820632bdae8e50165595706 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -1,42 +1,20 @@ package net.minecraft.server.level; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; -import com.mojang.datafixers.util.Either; import com.mojang.logging.LogUtils; -import it.unimi.dsi.fastutil.longs.Long2ByteMap; -import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2IntMap; -import it.unimi.dsi.fastutil.longs.Long2IntMaps; -import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import it.unimi.dsi.fastutil.longs.LongSet; +import it.unimi.dsi.fastutil.longs.*; import it.unimi.dsi.fastutil.objects.ObjectIterator; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectSet; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Iterator; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import javax.annotation.Nullable; import net.minecraft.core.SectionPos; import net.minecraft.util.SortedArraySet; -import net.minecraft.util.thread.ProcessorHandle; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; import org.slf4j.Logger; +import javax.annotation.Nullable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.Executor; public abstract class DistanceManager { @@ -52,7 +30,7 @@ public abstract class DistanceManager { private static final int INITIAL_TICKET_LIST_CAPACITY = 4; private static final int ENTITY_TICKING_LEVEL_THRESHOLD = 32; private static final int BLOCK_TICKING_LEVEL_THRESHOLD = 33; - final Long2ObjectMap> playersPerChunk = new Long2ObjectOpenHashMap(); + final Long2ObjectMap> playersPerChunk = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap()); // Paper - rewrite chunk system public static final int MOB_SPAWN_RANGE = 8; // private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8); // Paper - no longer used //private final TickingTracker tickingTicketsTracker = new TickingTracker(); // Paper - no longer used diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java index 0ae45cf5a084fd412305e8b2f5dabe608b4eb1c1..a2935994edc279d880ff26dd5cc4e33f1105acc8 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -4,43 +4,19 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.util.Either; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.function.BooleanSupplier; -import java.util.function.Consumer; -import java.util.function.Supplier; -import javax.annotation.Nullable; +import it.unimi.dsi.fastutil.objects.ObjectArraySet; +import it.unimi.dsi.fastutil.objects.ObjectSet; import net.minecraft.Util; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.network.protocol.Packet; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.util.VisibleForDebug; -import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.ai.village.poi.PoiManager; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.LocalMobCapCalculator; -import net.minecraft.world.level.NaturalSpawner; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; -import net.minecraft.world.level.chunk.ChunkSource; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.*; +import net.minecraft.world.level.chunk.*; import net.minecraft.world.level.chunk.storage.ChunkScanAccess; import net.minecraft.world.level.entity.ChunkStatusUpdateListener; import net.minecraft.world.level.levelgen.RandomState; @@ -48,7 +24,16 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp import net.minecraft.world.level.storage.DimensionDataStorage; import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.level.storage.LevelStorageSource; -import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper + +import javax.annotation.Nullable; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Supplier; public class ServerChunkCache extends ChunkSource { @@ -803,7 +788,7 @@ public class ServerChunkCache extends ChunkSource { //gameprofilerfiller.popPush("broadcast"); // Purpur //this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing // Purpur if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) { - ReferenceOpenHashSet copy = this.chunkMap.needsChangeBroadcasting.clone(); + ObjectSet copy = new ObjectArraySet<>(this.chunkMap.needsChangeBroadcasting); this.chunkMap.needsChangeBroadcasting.clear(); for (ChunkHolder holder : copy) { holder.broadcastChanges(holder.getFullChunkNowUnchecked()); // LevelChunks are NEVER unloaded diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java index 660693c6dc0ef86f4013df980b6d0c11c03e46cd..1ea9699ce1f77a551a45fc06dad55df4cc1a4f4d 100644 --- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java +++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java @@ -1,14 +1,9 @@ package net.minecraft.server.level; -import com.mojang.datafixers.util.Pair; +import ca.spottedleaf.starlight.common.light.StarLightEngine; import com.mojang.logging.LogUtils; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectList; -import it.unimi.dsi.fastutil.objects.ObjectListIterator; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.IntSupplier; -import javax.annotation.Nullable; +import io.papermc.paper.util.CoordinateUtils; +import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; import net.minecraft.Util; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; @@ -17,21 +12,17 @@ import net.minecraft.util.thread.ProcessorMailbox; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LightChunkGetter; +import net.minecraft.world.level.lighting.LayerLightEventListener; import net.minecraft.world.level.lighting.LevelLightEngine; import org.slf4j.Logger; -// Paper start -import ca.spottedleaf.starlight.common.light.StarLightEngine; -import io.papermc.paper.util.CoordinateUtils; +import javax.annotation.Nullable; +import java.util.concurrent.CompletableFuture; +import java.util.function.IntSupplier; import java.util.function.Supplier; -import net.minecraft.world.level.lighting.LayerLightEventListener; -import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArrayList; -import it.unimi.dsi.fastutil.longs.LongIterator; -import net.minecraft.world.level.chunk.ChunkStatus; // Paper end public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable { @@ -145,20 +136,30 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl return; } - final int references = this.chunksBeingWorkedOn.addTo(key, 1); + int references; + synchronized (this.chunksBeingWorkedOn){ + references = this.chunksBeingWorkedOn.addTo(key, 1); + } if (references == 0) { final ChunkPos pos = new ChunkPos(chunkX, chunkZ); world.getChunkSource().addRegionTicket(ca.spottedleaf.starlight.common.light.StarLightInterface.CHUNK_WORK_TICKET, pos, 0, pos); } updateFuture.thenAcceptAsync((final Void ignore) -> { - final int newReferences = this.chunksBeingWorkedOn.get(key); + int newReferences; + synchronized (this.chunksBeingWorkedOn){ + newReferences = this.chunksBeingWorkedOn.get(key); + } if (newReferences == 1) { - this.chunksBeingWorkedOn.remove(key); + synchronized (this.chunksBeingWorkedOn){ + this.chunksBeingWorkedOn.remove(key); + } final ChunkPos pos = new ChunkPos(chunkX, chunkZ); world.getChunkSource().removeRegionTicket(ca.spottedleaf.starlight.common.light.StarLightInterface.CHUNK_WORK_TICKET, pos, 0, pos); } else { - this.chunksBeingWorkedOn.put(key, newReferences - 1); + synchronized (this.chunksBeingWorkedOn){ + this.chunksBeingWorkedOn.put(key, newReferences - 1); + } } }, world.getChunkSource().chunkMap.mainThreadExecutor).whenComplete((final Void ignore, final Throwable thr) -> { if (thr != null) { diff --git a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java index 50a9f33aa31e9273c7c52d4bb2b02f0f884f7ba5..d5802cfe08f92b55ff1fd41648abda9ef2b7dd20 100644 --- a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java +++ b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java @@ -10,12 +10,14 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collector; import java.util.stream.Collectors; public class ClassInstanceMultiMap extends AbstractCollection { - private final Map, List> byClass = Maps.newHashMap(); + private final Map, List> byClass = Maps.newConcurrentMap(); private final Class baseClass; - private final List allInstances = Lists.newArrayList(); + private final List allInstances = Lists.newCopyOnWriteArrayList(); public ClassInstanceMultiMap(Class elementType) { this.baseClass = elementType; @@ -59,12 +61,16 @@ public class ClassInstanceMultiMap extends AbstractCollection { throw new IllegalArgumentException("Don't know how to search for " + type); } else { List 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) Collections.unmodifiableCollection(list); } } + public static Collector> toList() { + return Collectors.toCollection(CopyOnWriteArrayList::new); + } + @Override public Iterator iterator() { return (Iterator)(this.allInstances.isEmpty() ? Collections.emptyIterator() : Iterators.unmodifiableIterator(this.allInstances.iterator())); diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java index 83701fbfaa56a232593ee8f11a3afb8941238bfa..0c70810edace99bb5037d927388e055a514fcbde 100644 --- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java +++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java @@ -8,6 +8,7 @@ import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.StampedLock; import java.util.function.BooleanSupplier; import java.util.function.Supplier; import net.minecraft.util.profiling.metrics.MetricCategory; @@ -20,6 +21,7 @@ public abstract class BlockableEventLoop implements Profiler private final String name; private static final Logger LOGGER = LogUtils.getLogger(); private final Queue pendingRunnables = Queues.newConcurrentLinkedQueue(); + private final StampedLock lock = new StampedLock(); private int blockingCount; protected BlockableEventLoop(String name) { @@ -42,7 +44,12 @@ public abstract class BlockableEventLoop implements Profiler } public int getPendingTasksCount() { - return this.pendingRunnables.size(); + final long id = this.lock.readLock(); + try{ + return this.pendingRunnables.size(); + }finally { + this.lock.unlockRead(id); + } } @Override @@ -88,7 +95,12 @@ public abstract class BlockableEventLoop implements Profiler @Override public void tell(R runnable) { - this.pendingRunnables.add(runnable); + final long id = this.lock.writeLock(); + try { + this.pendingRunnables.add(runnable); + }finally { + this.lock.unlockWrite(id); + } LockSupport.unpark(this.getRunningThread()); } @@ -107,7 +119,12 @@ public abstract class BlockableEventLoop implements Profiler } protected void dropAllTasks() { - this.pendingRunnables.clear(); + final long id = this.lock.writeLock(); + try { + this.pendingRunnables.clear(); + }finally { + this.lock.unlockWrite(id); + } } protected void runAllTasks() { @@ -117,14 +134,19 @@ public abstract class BlockableEventLoop implements Profiler } public boolean pollTask() { - R runnable = this.pendingRunnables.peek(); - if (runnable == null) { - return false; - } else if (this.blockingCount == 0 && !this.shouldRun(runnable)) { - return false; - } else { - this.doRunTask(this.pendingRunnables.remove()); - return true; + final long id = this.lock.writeLock(); + try { + R runnable = this.pendingRunnables.peek(); + if (runnable == null) { + return false; + } else if (this.blockingCount == 0 && !this.shouldRun(runnable)) { + return false; + } else { + this.doRunTask(this.pendingRunnables.remove()); + return true; + } + }finally { + this.lock.unlockWrite(id); } } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 99912ae883227e1c0a0adc1edbb4c4baee4fe2bc..f33476a35706d7a236fe3bb178d166d568c07674 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -164,76 +164,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { } // Paper start - public static RandomSource SHARED_RANDOM = new RandomRandomSource(); - private static final class RandomRandomSource extends java.util.Random implements net.minecraft.world.level.levelgen.BitRandomSource { - private boolean locked = false; - - @Override - public synchronized void setSeed(long seed) { - if (locked) { - LOGGER.error("Ignoring setSeed on Entity.SHARED_RANDOM", new Throwable()); - } else { - super.setSeed(seed); - locked = true; - } - } - - @Override - public RandomSource fork() { - return new net.minecraft.world.level.levelgen.LegacyRandomSource(this.nextLong()); - } - - @Override - public net.minecraft.world.level.levelgen.PositionalRandomFactory forkPositional() { - return new net.minecraft.world.level.levelgen.LegacyRandomSource.LegacyPositionalRandomFactory(this.nextLong()); - } - - // these below are added to fix reobf issues that I don't wanna deal with right now - @Override - public int next(int bits) { - return super.next(bits); - } - - @Override - public int nextInt(int origin, int bound) { - return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(origin, bound); - } - - @Override - public long nextLong() { - return net.minecraft.world.level.levelgen.BitRandomSource.super.nextLong(); - } - - @Override - public int nextInt() { - return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(); - } - - @Override - public int nextInt(int bound) { - return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(bound); - } - - @Override - public boolean nextBoolean() { - return net.minecraft.world.level.levelgen.BitRandomSource.super.nextBoolean(); - } - - @Override - public float nextFloat() { - return net.minecraft.world.level.levelgen.BitRandomSource.super.nextFloat(); - } - - @Override - public double nextDouble() { - return net.minecraft.world.level.levelgen.BitRandomSource.super.nextDouble(); - } - - @Override - public double nextGaussian() { - return super.nextGaussian(); - } - } + public static RandomSource SHARED_RANDOM = RandomSource.create(); // Paper end public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper diff --git a/src/main/java/net/minecraft/world/level/entity/EntityLookup.java b/src/main/java/net/minecraft/world/level/entity/EntityLookup.java index d45d832232be5017dde53816191c2b1830a0da32..f73f78e2f7c6e3eae66f7608a92854b3246e153d 100644 --- a/src/main/java/net/minecraft/world/level/entity/EntityLookup.java +++ b/src/main/java/net/minecraft/world/level/entity/EntityLookup.java @@ -8,13 +8,15 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import java.util.Map; import java.util.UUID; import javax.annotation.Nullable; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import net.minecraft.util.AbortableIterationConsumer; import org.slf4j.Logger; public class EntityLookup { private static final Logger LOGGER = LogUtils.getLogger(); - private final Int2ObjectMap byId = new Int2ObjectLinkedOpenHashMap<>(); - private final Map byUuid = Maps.newHashMap(); + private final Int2ObjectMap byId = Int2ObjectMaps.synchronize(new Int2ObjectLinkedOpenHashMap<>()); + private final Map byUuid = Maps.newConcurrentMap(); public void getEntities(EntityTypeTest filter, AbortableIterationConsumer consumer) { for(T entityAccess : this.byId.values()) { diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java index 57fcf3910f45ce371ac2e237b277b1034caaac4e..00f7b58db5948f4d7c7f07736d8fcf1972009c77 100644 --- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java +++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java @@ -1,29 +1,22 @@ package net.minecraft.world.level.entity; -import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import java.util.Iterator; +import java.util.Set; import java.util.function.Consumer; -import javax.annotation.Nullable; +import it.unimi.dsi.fastutil.objects.ObjectArraySet; +import it.unimi.dsi.fastutil.objects.ObjectSets; import net.minecraft.world.entity.Entity; public class EntityTickList { - public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? // Pufferfish - private->public - - private void ensureActiveIsNotIterated() { - // Paper - replace with better logic, do not delay removals - - } + public final Set entities = ObjectSets.synchronize(new ObjectArraySet<>()); public void add(Entity entity) { io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist addition"); // Paper - this.ensureActiveIsNotIterated(); this.entities.add(entity); // Paper - replace with better logic, do not delay removals/additions } public void remove(Entity entity) { io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist removal"); // Paper - this.ensureActiveIsNotIterated(); this.entities.remove(entity); // Paper - replace with better logic, do not delay removals/additions } @@ -33,16 +26,8 @@ public class EntityTickList { public void forEach(Consumer 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 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 implements AutoCloseable { static final Logger LOGGER = LogUtils.getLogger(); - final Set knownUuids = Sets.newHashSet(); + final Set knownUuids = Sets.newConcurrentHashSet(); final LevelCallback callbacks; public final EntityPersistentStorage permanentStorage; private final EntityLookup visibleEntityStorage = new EntityLookup<>(); final EntitySectionStorage sectionStorage; private final LevelEntityGetter entityGetter; - private final Long2ObjectMap chunkVisibility = new Long2ObjectOpenHashMap(); - private final Long2ObjectMap chunkLoadStatuses = new Long2ObjectOpenHashMap(); - private final LongSet chunksToUnload = new LongOpenHashSet(); + private final Long2ObjectMap chunkVisibility = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap()); + private final Long2ObjectMap chunkLoadStatuses = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap()); + private final LongSet chunksToUnload = LongSets.synchronize(new LongOpenHashSet()); private final Queue> loadingInbox = Queues.newConcurrentLinkedQueue(); public PersistentEntitySectionManager(Class entityClass, LevelCallback handler, EntityPersistentStorage dataAccess) { diff --git a/src/main/java/net/minecraft/world/level/levelgen/LegacyRandomSource.java b/src/main/java/net/minecraft/world/level/levelgen/LegacyRandomSource.java index daa03360dd7044f10b20f36023b305dc7e0bb7df..35de9e9a9d211b16a8b945bc512c128709ec6bfc 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/LegacyRandomSource.java +++ b/src/main/java/net/minecraft/world/level/levelgen/LegacyRandomSource.java @@ -19,17 +19,17 @@ public class LegacyRandomSource implements BitRandomSource { } @Override - public RandomSource fork() { + public synchronized RandomSource fork() { return new LegacyRandomSource(this.nextLong()); } @Override - public PositionalRandomFactory forkPositional() { + public synchronized PositionalRandomFactory forkPositional() { return new LegacyRandomSource.LegacyPositionalRandomFactory(this.nextLong()); } @Override - public void setSeed(long seed) { + public synchronized void setSeed(long seed) { if (!this.seed.compareAndSet(this.seed.get(), (seed ^ 25214903917L) & 281474976710655L)) { throw ThreadingDetector.makeThreadingException("LegacyRandomSource", (Thread)null); } else { @@ -38,7 +38,7 @@ public class LegacyRandomSource implements BitRandomSource { } @Override - public int next(int bits) { + public synchronized int next(int bits) { long l = this.seed.get(); long m = l * 25214903917L + 11L & 281474976710655L; if (!this.seed.compareAndSet(l, m)) { @@ -49,7 +49,7 @@ public class LegacyRandomSource implements BitRandomSource { } @Override - public double nextGaussian() { + public synchronized double nextGaussian() { return this.gaussianSource.nextGaussian(); } @@ -61,21 +61,21 @@ public class LegacyRandomSource implements BitRandomSource { } @Override - public RandomSource at(int x, int y, int z) { + public synchronized RandomSource at(int x, int y, int z) { long l = Mth.getSeed(x, y, z); long m = l ^ this.seed; return new LegacyRandomSource(m); } @Override - public RandomSource fromHashOf(String seed) { + public synchronized RandomSource fromHashOf(String seed) { int i = seed.hashCode(); return new LegacyRandomSource((long)i ^ this.seed); } @VisibleForTesting @Override - public void parityConfigString(StringBuilder info) { + public synchronized void parityConfigString(StringBuilder info) { info.append("LegacyPositionalRandomFactory{").append(this.seed).append("}"); } } diff --git a/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java b/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java index 3d5ce92c77bc107e2ec2f54dc849b99c3abf9718..88d78f77740ee436fedd5159f8bafe91c1eb5ec1 100644 --- a/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java +++ b/src/main/java/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java @@ -1,17 +1,16 @@ package net.minecraft.world.level.lighting; -import it.unimi.dsi.fastutil.longs.Long2ByteMap; -import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArrayList; -import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; -import it.unimi.dsi.fastutil.longs.LongList; +import it.unimi.dsi.fastutil.longs.*; + +import java.util.Deque; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.function.LongPredicate; import net.minecraft.util.Mth; public abstract class DynamicGraphMinFixedPoint { private static final int NO_COMPUTED_LEVEL = 255; private final int levelCount; - private final LongLinkedOpenHashSet[] queues; + private final Deque[] 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 longLinkedOpenHashSet = this.queues[this.firstQueuedLevel]; + long l = longLinkedOpenHashSet.removeFirst(); int i = Mth.clamp(this.getLevel(l), 0, this.levelCount - 1); if (longLinkedOpenHashSet.isEmpty()) { this.checkFirstQueuedLevel(this.levelCount); diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java index b1c594dc6a6b8a6c737b99272acab9e7dbd0ed63..a097e00bd62f53630568f68854d3a34300012277 100644 --- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java @@ -4,6 +4,8 @@ import com.mojang.logging.LogUtils; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.locks.StampedLock; import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -17,9 +19,11 @@ public class CollectingNeighborUpdater implements NeighborUpdater { private final Level level; private final int maxChainedNeighborUpdates; private final ArrayDeque stack = new ArrayDeque<>(); - private final List addedThisLayer = new ArrayList<>(); + private final List addedThisLayer = new CopyOnWriteArrayList<>(); private int count = 0; + private final StampedLock lock = new StampedLock(); + public CollectingNeighborUpdater(Level world, int maxChainDepth) { this.level = world; this.maxChainedNeighborUpdates = maxChainDepth; @@ -49,14 +53,19 @@ public class CollectingNeighborUpdater implements NeighborUpdater { boolean bl = this.count > 0; boolean bl2 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates; ++this.count; - if (!bl2) { - if (bl) { - this.addedThisLayer.add(entry); - } else { - this.stack.push(entry); + final long lockId = this.lock.writeLock(); + try { + if (!bl2) { + if (bl) { + this.addedThisLayer.add(entry); + } else { + this.stack.push(entry); + } + } else if (this.count - 1 == this.maxChainedNeighborUpdates) { + LOGGER.error("Too many chained neighbor updates. Skipping the rest. First skipped position: " + pos.toShortString()); } - } else if (this.count - 1 == this.maxChainedNeighborUpdates) { - LOGGER.error("Too many chained neighbor updates. Skipping the rest. First skipped position: " + pos.toShortString()); + }finally { + this.lock.unlockWrite(lockId); } if (!bl) { @@ -66,28 +75,31 @@ public class CollectingNeighborUpdater implements NeighborUpdater { } private void runUpdates() { + final long lockid = this.lock.writeLock(); try { - while(!this.stack.isEmpty() || !this.addedThisLayer.isEmpty()) { - for(int i = this.addedThisLayer.size() - 1; i >= 0; --i) { - this.stack.push(this.addedThisLayer.get(i)); - } - - this.addedThisLayer.clear(); - CollectingNeighborUpdater.NeighborUpdates neighborUpdates = this.stack.peek(); - - while(this.addedThisLayer.isEmpty()) { - if (!neighborUpdates.runNext(this.level)) { - this.stack.pop(); - break; + try { + while(!this.stack.isEmpty() || !this.addedThisLayer.isEmpty()) { + for(int i = this.addedThisLayer.size() - 1; i >= 0; --i) { + this.stack.push(this.addedThisLayer.get(i)); + } + this.addedThisLayer.clear(); + CollectingNeighborUpdater.NeighborUpdates neighborUpdates = this.stack.peek(); + + while(this.addedThisLayer.isEmpty()) { + if (!neighborUpdates.runNext(this.level)) { + this.stack.pop(); + break; + } } } + } finally { + this.stack.clear(); + this.addedThisLayer.clear(); + this.count = 0; } - } finally { - this.stack.clear(); - this.addedThisLayer.clear(); - this.count = 0; + }finally { + this.lock.unlockWrite(lockid); } - } static record FullNeighborUpdate(BlockState state, BlockPos pos, Block block, BlockPos neighborPos, boolean movedByPiston) implements CollectingNeighborUpdater.NeighborUpdates {