mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-27 15:00:13 +01:00
net/minecraft/world/level/chunk/
This commit is contained in:
parent
c31ab10475
commit
a3bd0b2bbb
15 changed files with 673 additions and 875 deletions
|
@ -1,43 +1,45 @@
|
||||||
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
|
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||||
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
|
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||||
@@ -65,7 +65,7 @@
|
@@ -64,7 +_,7 @@
|
||||||
protected final ShortList[] postProcessing;
|
protected final ShortList[] postProcessing;
|
||||||
private volatile boolean unsaved;
|
private volatile boolean unsaved;
|
||||||
private volatile boolean isLightCorrect;
|
private volatile boolean isLightCorrect;
|
||||||
- protected final ChunkPos chunkPos;
|
- protected final ChunkPos chunkPos;
|
||||||
+ protected final ChunkPos chunkPos; public final long coordinateKey; public final int locX; public final int locZ; // Paper - cache coordinate key
|
+ protected final ChunkPos chunkPos; public final long coordinateKey; public final int locX; public final int locZ; // Paper - cache coordinate key
|
||||||
private long inhabitedTime;
|
private long inhabitedTime;
|
||||||
/** @deprecated */
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -85,8 +85,14 @@
|
@Deprecated
|
||||||
|
@@ -82,6 +_,11 @@
|
||||||
|
public final Map<BlockPos, BlockEntity> blockEntities = new Object2ObjectOpenHashMap<>();
|
||||||
protected final LevelHeightAccessor levelHeightAccessor;
|
protected final LevelHeightAccessor levelHeightAccessor;
|
||||||
protected final LevelChunkSection[] sections;
|
protected final LevelChunkSection[] sections;
|
||||||
|
|
||||||
+ // CraftBukkit start - SPIGOT-6814: move to IChunkAccess to account for 1.17 to 1.18 chunk upgrading.
|
+ // CraftBukkit start - SPIGOT-6814: move to IChunkAccess to account for 1.17 to 1.18 chunk upgrading.
|
||||||
+ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
+ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
||||||
+ public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(ChunkAccess.DATA_TYPE_REGISTRY);
|
+ public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(ChunkAccess.DATA_TYPE_REGISTRY);
|
||||||
+ // CraftBukkit end
|
+ // CraftBukkit end
|
||||||
+
|
+ public final Registry<Biome> biomeRegistry; // CraftBukkit
|
||||||
public ChunkAccess(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor heightLimitView, Registry<Biome> biomeRegistry, long inhabitedTime, @Nullable LevelChunkSection[] sectionArray, @Nullable BlendingData blendingData) {
|
|
||||||
- this.chunkPos = pos;
|
public ChunkAccess(
|
||||||
+ this.locX = pos.x; this.locZ = pos.z; // Paper - reduce need for field lookups
|
ChunkPos chunkPos,
|
||||||
+ this.chunkPos = pos; this.coordinateKey = ChunkPos.asLong(locX, locZ); // Paper - cache long key
|
@@ -92,7 +_,8 @@
|
||||||
|
@Nullable LevelChunkSection[] sections,
|
||||||
|
@Nullable BlendingData blendingData
|
||||||
|
) {
|
||||||
|
- this.chunkPos = chunkPos;
|
||||||
|
+ this.locX = chunkPos.x; this.locZ = chunkPos.z; // Paper - reduce need for field lookups
|
||||||
|
+ this.chunkPos = chunkPos; this.coordinateKey = ChunkPos.asLong(locX, locZ); // Paper - cache long key
|
||||||
this.upgradeData = upgradeData;
|
this.upgradeData = upgradeData;
|
||||||
this.levelHeightAccessor = heightLimitView;
|
this.levelHeightAccessor = levelHeightAccessor;
|
||||||
this.sections = new LevelChunkSection[heightLimitView.getSectionsCount()];
|
this.sections = new LevelChunkSection[levelHeightAccessor.getSectionsCount()];
|
||||||
@@ -103,7 +109,11 @@
|
@@ -109,6 +_,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkAccess.replaceMissingSections(biomeRegistry, this.sections);
|
replaceMissingSections(biomeRegistry, this.sections);
|
||||||
+ // CraftBukkit start
|
+ this.biomeRegistry = biomeRegistry; // Craftbukkit
|
||||||
+ this.biomeRegistry = biomeRegistry;
|
|
||||||
}
|
}
|
||||||
+ public final Registry<Biome> biomeRegistry;
|
|
||||||
+ // CraftBukkit end
|
|
||||||
|
|
||||||
private static void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sectionArray) {
|
private static void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sections) {
|
||||||
for (int i = 0; i < sectionArray.length; ++i) {
|
@@ -273,6 +_,7 @@
|
||||||
@@ -275,6 +285,7 @@
|
|
||||||
public boolean tryMarkSaved() {
|
public boolean tryMarkSaved() {
|
||||||
if (this.unsaved) {
|
if (this.unsaved) {
|
||||||
this.unsaved = false;
|
this.unsaved = false;
|
||||||
|
@ -45,7 +47,7 @@
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -282,7 +293,7 @@
|
@@ -280,7 +_,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUnsaved() {
|
public boolean isUnsaved() {
|
||||||
|
@ -54,15 +56,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract ChunkStatus getPersistedStatus();
|
public abstract ChunkStatus getPersistedStatus();
|
||||||
@@ -458,10 +469,31 @@
|
@@ -446,6 +_,26 @@
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
crashreportsystemdetails.setDetail("Location", () -> {
|
}
|
||||||
return CrashReportCategory.formatLocation(this, biomeX, biomeY, biomeZ);
|
}
|
||||||
+ });
|
|
||||||
+ throw new ReportedException(crashreport);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // CraftBukkit start
|
+ // CraftBukkit start
|
||||||
+ public void setBiome(int i, int j, int k, Holder<Biome> biome) {
|
+ public void setBiome(int i, int j, int k, Holder<Biome> biome) {
|
||||||
+ try {
|
+ try {
|
||||||
|
@ -78,11 +75,11 @@
|
||||||
+
|
+
|
||||||
+ crashreportsystemdetails.setDetail("Location", () -> {
|
+ crashreportsystemdetails.setDetail("Location", () -> {
|
||||||
+ return CrashReportCategory.formatLocation(this, i, j, k);
|
+ return CrashReportCategory.formatLocation(this, i, j, k);
|
||||||
});
|
+ });
|
||||||
throw new ReportedException(crashreport);
|
+ throw new ReportedException(crashreport);
|
||||||
}
|
+ }
|
||||||
}
|
+ }
|
||||||
+ // CraftBukkit end
|
+ // CraftBukkit end
|
||||||
|
|
||||||
public void fillBiomesFromNoise(BiomeResolver biomeSupplier, Climate.Sampler sampler) {
|
public void fillBiomesFromNoise(BiomeResolver resolver, Climate.Sampler sampler) {
|
||||||
ChunkPos chunkcoordintpair = this.getPos();
|
ChunkPos pos = this.getPos();
|
|
@ -0,0 +1,148 @@
|
||||||
|
--- a/net/minecraft/world/level/chunk/ChunkGenerator.java
|
||||||
|
+++ b/net/minecraft/world/level/chunk/ChunkGenerator.java
|
||||||
|
@@ -104,8 +_,8 @@
|
||||||
|
|
||||||
|
protected abstract MapCodec<? extends ChunkGenerator> codec();
|
||||||
|
|
||||||
|
- public ChunkGeneratorStructureState createState(HolderLookup<StructureSet> structureSetLookup, RandomState randomState, long seed) {
|
||||||
|
- return ChunkGeneratorStructureState.createForNormal(randomState, seed, this.biomeSource, structureSetLookup);
|
||||||
|
+ public ChunkGeneratorStructureState createState(HolderLookup<StructureSet> structureSetLookup, RandomState randomState, long seed, org.spigotmc.SpigotWorldConfig conf) { // Spigot
|
||||||
|
+ return ChunkGeneratorStructureState.createForNormal(randomState, seed, this.biomeSource, structureSetLookup, conf); // Spigot
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> getTypeNameForDataFixer() {
|
||||||
|
@@ -127,6 +_,24 @@
|
||||||
|
public Pair<BlockPos, Holder<Structure>> findNearestMapStructure(
|
||||||
|
ServerLevel level, HolderSet<Structure> structure, BlockPos pos, int searchRadius, boolean skipKnownStructures
|
||||||
|
) {
|
||||||
|
+ // Paper start - StructuresLocateEvent
|
||||||
|
+ final org.bukkit.World bukkitWorld = level.getWorld();
|
||||||
|
+ final org.bukkit.Location origin = io.papermc.paper.util.MCUtil.toLocation(level, pos);
|
||||||
|
+ final List<org.bukkit.generator.structure.Structure> apiStructures = structure.stream().map(Holder::value).map(nms -> org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(nms)).toList();
|
||||||
|
+ if (!apiStructures.isEmpty()) {
|
||||||
|
+ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, searchRadius, skipKnownStructures);
|
||||||
|
+ if (!event.callEvent()) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ if (event.getResult() != null) {
|
||||||
|
+ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), level.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(event.getResult().structure())));
|
||||||
|
+ }
|
||||||
|
+ pos = io.papermc.paper.util.MCUtil.toBlockPosition(event.getOrigin());
|
||||||
|
+ searchRadius = event.getRadius();
|
||||||
|
+ skipKnownStructures = event.shouldFindUnexplored();
|
||||||
|
+ structure = HolderSet.direct(api -> level.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(api)), event.getStructures());
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
ChunkGeneratorStructureState generatorState = level.getChunkSource().getGeneratorState();
|
||||||
|
Map<StructurePlacement, Set<Holder<Structure>>> map = new Object2ObjectArrayMap<>();
|
||||||
|
|
||||||
|
@@ -222,6 +_,7 @@
|
||||||
|
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||||
|
|
||||||
|
for (ChunkPos chunkPos : ringPositionsFor) {
|
||||||
|
+ if (!level.paperConfig().environment.locateStructuresOutsideWorldBorder && !level.getWorldBorder().isChunkInBounds(chunkPos.x, chunkPos.z)) { continue; } // Paper - Bound treasure maps to world border
|
||||||
|
mutableBlockPos.set(SectionPos.sectionToBlockCoord(chunkPos.x, 8), 32, SectionPos.sectionToBlockCoord(chunkPos.z, 8));
|
||||||
|
double d1 = mutableBlockPos.distSqr(pos);
|
||||||
|
boolean flag = pair == null || d1 < d;
|
||||||
|
@@ -255,11 +_,15 @@
|
||||||
|
int spacing = spreadPlacement.spacing();
|
||||||
|
|
||||||
|
for (int i = -z; i <= z; i++) {
|
||||||
|
- boolean flag = i == -z || i == z;
|
||||||
|
+ // Paper start - Perf: iterate over border chunks instead of entire square chunk area
|
||||||
|
+ final int radius = z;
|
||||||
|
+ boolean flag = i == -z || i == z; final boolean onBorderAlongZAxis = flag; // Paper - OBFHELPER
|
||||||
|
|
||||||
|
- for (int i1 = -z; i1 <= z; i1++) {
|
||||||
|
- boolean flag1 = i1 == -z || i1 == z;
|
||||||
|
- if (flag || flag1) {
|
||||||
|
+ for (int i1 = -radius; i1 <= radius; i1 += onBorderAlongZAxis ? 1 : radius * 2) {
|
||||||
|
+ // boolean flag1 = i1 == -z || i1 == z;
|
||||||
|
+ // if (flag || flag1) {
|
||||||
|
+ if (true) {
|
||||||
|
+ // Paper end - Perf: iterate over border chunks instead of entire square chunk area
|
||||||
|
int i2 = x + spacing * i;
|
||||||
|
int i3 = y + spacing * i1;
|
||||||
|
ChunkPos potentialStructureChunk = spreadPlacement.getPotentialStructureChunk(seed, i2, i3);
|
||||||
|
@@ -312,7 +_,7 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void applyBiomeDecoration(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager) {
|
||||||
|
+ public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunk, StructureManager structureManager) { // CraftBukkit - rename
|
||||||
|
ChunkPos pos = chunk.getPos();
|
||||||
|
if (!SharedConstants.debugVoidTerrain(pos)) {
|
||||||
|
SectionPos sectionPos = SectionPos.of(pos, level.getMinSectionY());
|
||||||
|
@@ -385,7 +_,14 @@
|
||||||
|
int i3 = ints[i2];
|
||||||
|
PlacedFeature placedFeature = stepFeatureData1.features().get(i3);
|
||||||
|
Supplier<String> supplier1 = () -> registry1.getResourceKey(placedFeature).map(Object::toString).orElseGet(placedFeature::toString);
|
||||||
|
- worldgenRandom.setFeatureSeed(l, i3, i);
|
||||||
|
+ // Paper start - Configurable feature seeds; change populationSeed used in random
|
||||||
|
+ long featurePopulationSeed = i;
|
||||||
|
+ final long configFeatureSeed = level.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(placedFeature.feature());
|
||||||
|
+ if (configFeatureSeed != -1) {
|
||||||
|
+ featurePopulationSeed = worldgenRandom.setDecorationSeed(configFeatureSeed, blockPos.getX(), blockPos.getZ()); // See seededrandom.setDecorationSeed from above
|
||||||
|
+ }
|
||||||
|
+ worldgenRandom.setFeatureSeed(featurePopulationSeed, i3, i);
|
||||||
|
+ // Paper end - Configurable feature seeds
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier1);
|
||||||
|
@@ -407,6 +_,32 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ // CraftBukkit start
|
||||||
|
+ public void applyBiomeDecoration(WorldGenLevel world, ChunkAccess chunk, StructureManager structureAccessor) {
|
||||||
|
+ this.applyBiomeDecoration(world, chunk, structureAccessor, true);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
|
+ if (vanilla) {
|
||||||
|
+ this.addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ org.bukkit.World world = generatoraccessseed.getMinecraftWorld().getWorld();
|
||||||
|
+ // only call when a populator is present (prevents unnecessary entity conversion)
|
||||||
|
+ if (!world.getPopulators().isEmpty()) {
|
||||||
|
+ org.bukkit.craftbukkit.generator.CraftLimitedRegion limitedRegion = new org.bukkit.craftbukkit.generator.CraftLimitedRegion(generatoraccessseed, ichunkaccess.getPos());
|
||||||
|
+ int x = ichunkaccess.getPos().x;
|
||||||
|
+ int z = ichunkaccess.getPos().z;
|
||||||
|
+ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) {
|
||||||
|
+ WorldgenRandom seededrandom = new WorldgenRandom(new net.minecraft.world.level.levelgen.LegacyRandomSource(generatoraccessseed.getSeed()));
|
||||||
|
+ seededrandom.setDecorationSeed(generatoraccessseed.getSeed(), x, z);
|
||||||
|
+ populator.populate(world, new org.bukkit.craftbukkit.util.RandomSourceWrapper.RandomWrapper(seededrandom), x, z, limitedRegion);
|
||||||
|
+ }
|
||||||
|
+ limitedRegion.saveEntities();
|
||||||
|
+ limitedRegion.breakLink();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // CraftBukkit end
|
||||||
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess chunk) {
|
||||||
|
ChunkPos pos = chunk.getPos();
|
||||||
|
@@ -483,7 +_,7 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (structurePlacement.isStructureChunk(structureState, pos.x, pos.z)) {
|
||||||
|
+ if (structurePlacement.isStructureChunk(structureState, pos.x, pos.z, structurePlacement instanceof net.minecraft.world.level.chunk.ChunkGeneratorStructureState.KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs
|
||||||
|
if (list.size() == 1) {
|
||||||
|
this.tryGenerateStructure(
|
||||||
|
list.get(0),
|
||||||
|
@@ -577,6 +_,14 @@
|
||||||
|
predicate
|
||||||
|
);
|
||||||
|
if (structureStart.isValid()) {
|
||||||
|
+ // CraftBukkit start
|
||||||
|
+ BoundingBox box = structureStart.getBoundingBox();
|
||||||
|
+ org.bukkit.event.world.AsyncStructureSpawnEvent event = new org.bukkit.event.world.AsyncStructureSpawnEvent(structureStart.level.getMinecraftWorld().getWorld(), org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(structure), new org.bukkit.util.BoundingBox(box.minX(), box.minY(), box.minZ(), box.maxX(), box.maxY(), box.maxZ()), chunkPos.x, chunkPos.z);
|
||||||
|
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
|
||||||
|
+ if (event.isCancelled()) {
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ // CraftBukkit end
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, structureStart, chunk);
|
||||||
|
return true;
|
||||||
|
} else {
|
|
@ -1,53 +1,38 @@
|
||||||
--- a/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
|
--- a/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
|
||||||
+++ b/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
|
+++ b/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
|
||||||
@@ -1,3 +1,4 @@
|
@@ -1,3 +_,4 @@
|
||||||
+// mc-dev import
|
+// mc-dev import
|
||||||
package net.minecraft.world.level.chunk;
|
package net.minecraft.world.level.chunk;
|
||||||
|
|
||||||
import com.google.common.base.Stopwatch;
|
import com.google.common.base.Stopwatch;
|
||||||
@@ -33,6 +34,11 @@
|
@@ -41,22 +_,109 @@
|
||||||
import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement;
|
private final Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap<>();
|
||||||
import org.slf4j.Logger;
|
|
||||||
|
|
||||||
+// Spigot start
|
|
||||||
+import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
|
||||||
+import org.spigotmc.SpigotWorldConfig;
|
|
||||||
+// Spigot end
|
|
||||||
+
|
|
||||||
public class ChunkGeneratorStructureState {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LogUtils.getLogger();
|
|
||||||
@@ -44,22 +50,109 @@
|
|
||||||
private final Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap();
|
|
||||||
private boolean hasGeneratedPositions;
|
private boolean hasGeneratedPositions;
|
||||||
private final List<Holder<StructureSet>> possibleStructureSets;
|
private final List<Holder<StructureSet>> possibleStructureSets;
|
||||||
+ public final SpigotWorldConfig conf; // Paper - Add missing structure set seed configs
|
+ public final org.spigotmc.SpigotWorldConfig conf; // Paper - Add missing structure set seed configs
|
||||||
|
|
||||||
- public static ChunkGeneratorStructureState createForFlat(RandomState noiseConfig, long seed, BiomeSource biomeSource, Stream<Holder<StructureSet>> structureSets) {
|
public static ChunkGeneratorStructureState createForFlat(
|
||||||
- List<Holder<StructureSet>> list = structureSets.filter((holder) -> {
|
- RandomState randomState, long levelSeed, BiomeSource biomeSource, Stream<Holder<StructureSet>> structureSets
|
||||||
- return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder.value(), biomeSource);
|
+ RandomState randomState, long levelSeed, BiomeSource biomeSource, Stream<Holder<StructureSet>> structureSets, org.spigotmc.SpigotWorldConfig conf // Spigot
|
||||||
+ public static ChunkGeneratorStructureState createForFlat(RandomState randomstate, long i, BiomeSource worldchunkmanager, Stream<Holder<StructureSet>> stream, SpigotWorldConfig conf) { // Spigot
|
) {
|
||||||
+ List<Holder<StructureSet>> list = stream.filter((holder) -> {
|
List<Holder<StructureSet>> list = structureSets.filter(structureSet -> hasBiomesForStructureSet(structureSet.value(), biomeSource)).toList();
|
||||||
+ return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder.value(), worldchunkmanager);
|
- return new ChunkGeneratorStructureState(randomState, biomeSource, levelSeed, 0L, list);
|
||||||
}).toList();
|
+ return new ChunkGeneratorStructureState(randomState, biomeSource, levelSeed, 0L, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot
|
||||||
|
|
||||||
- return new ChunkGeneratorStructureState(noiseConfig, biomeSource, seed, 0L, list);
|
|
||||||
+ return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, 0L, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- public static ChunkGeneratorStructureState createForNormal(RandomState noiseConfig, long seed, BiomeSource biomeSource, HolderLookup<StructureSet> structureSetRegistry) {
|
public static ChunkGeneratorStructureState createForNormal(
|
||||||
- List<Holder<StructureSet>> list = (List) structureSetRegistry.listElements().filter((holder_c) -> {
|
- RandomState randomState, long seed, BiomeSource biomeSource, HolderLookup<StructureSet> structureSetLookup
|
||||||
- return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder_c.value(), biomeSource);
|
+ RandomState randomState, long seed, BiomeSource biomeSource, HolderLookup<StructureSet> structureSetLookup, org.spigotmc.SpigotWorldConfig conf // Spigot
|
||||||
+ public static ChunkGeneratorStructureState createForNormal(RandomState randomstate, long i, BiomeSource worldchunkmanager, HolderLookup<StructureSet> holderlookup, SpigotWorldConfig conf) { // Spigot
|
) {
|
||||||
+ List<Holder<StructureSet>> list = (List) holderlookup.listElements().filter((holder_c) -> {
|
List<Holder<StructureSet>> list = structureSetLookup.listElements()
|
||||||
+ return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder_c.value(), worldchunkmanager);
|
.filter(structureSet -> hasBiomesForStructureSet(structureSet.value(), biomeSource))
|
||||||
}).collect(Collectors.toUnmodifiableList());
|
.collect(Collectors.toUnmodifiableList());
|
||||||
|
- return new ChunkGeneratorStructureState(randomState, biomeSource, seed, seed, list);
|
||||||
- return new ChunkGeneratorStructureState(noiseConfig, biomeSource, seed, seed, list);
|
- }
|
||||||
+ return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, i, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot
|
+ return new ChunkGeneratorStructureState(randomState, biomeSource, seed, seed, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot
|
||||||
+ }
|
+ }
|
||||||
+ // Paper start - Add missing structure set seed configs; horrible hack because spigot creates a ton of direct Holders which lose track of the identifying key
|
+ // Paper start - Add missing structure set seed configs; horrible hack because spigot creates a ton of direct Holders which lose track of the identifying key
|
||||||
+ public static final class KeyedRandomSpreadStructurePlacement extends RandomSpreadStructurePlacement {
|
+ public static final class KeyedRandomSpreadStructurePlacement extends net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement {
|
||||||
+ public final net.minecraft.resources.ResourceKey<StructureSet> key;
|
+ public final net.minecraft.resources.ResourceKey<StructureSet> key;
|
||||||
+ public KeyedRandomSpreadStructurePlacement(net.minecraft.resources.ResourceKey<StructureSet> key, net.minecraft.core.Vec3i locateOffset, FrequencyReductionMethod frequencyReductionMethod, float frequency, int salt, java.util.Optional<StructurePlacement.ExclusionZone> exclusionZone, int spacing, int separation, net.minecraft.world.level.levelgen.structure.placement.RandomSpreadType spreadType) {
|
+ public KeyedRandomSpreadStructurePlacement(net.minecraft.resources.ResourceKey<StructureSet> key, net.minecraft.core.Vec3i locateOffset, FrequencyReductionMethod frequencyReductionMethod, float frequency, int salt, java.util.Optional<StructurePlacement.ExclusionZone> exclusionZone, int spacing, int separation, net.minecraft.world.level.levelgen.structure.placement.RandomSpreadType spreadType) {
|
||||||
+ super(locateOffset, frequencyReductionMethod, frequency, salt, exclusionZone, spacing, separation, spreadType);
|
+ super(locateOffset, frequencyReductionMethod, frequency, salt, exclusionZone, spacing, separation, spreadType);
|
||||||
|
@ -57,11 +42,11 @@
|
||||||
+ // Paper end - Add missing structure set seed configs
|
+ // Paper end - Add missing structure set seed configs
|
||||||
+
|
+
|
||||||
+ // Spigot start
|
+ // Spigot start
|
||||||
+ private static List<Holder<StructureSet>> injectSpigot(List<Holder<StructureSet>> list, SpigotWorldConfig conf) {
|
+ private static List<Holder<StructureSet>> injectSpigot(List<Holder<StructureSet>> list, org.spigotmc.SpigotWorldConfig conf) {
|
||||||
+ return list.stream().map((holder) -> {
|
+ return list.stream().map((holder) -> {
|
||||||
+ StructureSet structureset = holder.value();
|
+ StructureSet structureset = holder.value();
|
||||||
+ final Holder<StructureSet> newHolder; // Paper - Add missing structure set seed configs
|
+ final Holder<StructureSet> newHolder; // Paper - Add missing structure set seed configs
|
||||||
+ if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig && holder.unwrapKey().orElseThrow().location().getNamespace().equals(net.minecraft.resources.ResourceLocation.DEFAULT_NAMESPACE)) { // Paper - Add missing structure set seed configs; check namespace cause datapacks could add structure sets with the same path
|
+ if (structureset.placement() instanceof net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement randomConfig && holder.unwrapKey().orElseThrow().location().getNamespace().equals(net.minecraft.resources.ResourceLocation.DEFAULT_NAMESPACE)) { // Paper - Add missing structure set seed configs; check namespace cause datapacks could add structure sets with the same path
|
||||||
+ String name = holder.unwrapKey().orElseThrow().location().getPath();
|
+ String name = holder.unwrapKey().orElseThrow().location().getPath();
|
||||||
+ int seed = randomConfig.salt;
|
+ int seed = randomConfig.salt;
|
||||||
+
|
+
|
||||||
|
@ -130,46 +115,47 @@
|
||||||
+ return newHolder;
|
+ return newHolder;
|
||||||
+ // Paper end - Add missing structure set seed configs
|
+ // Paper end - Add missing structure set seed configs
|
||||||
+ }).collect(Collectors.toUnmodifiableList());
|
+ }).collect(Collectors.toUnmodifiableList());
|
||||||
}
|
+ }
|
||||||
+ // Spigot end
|
+ // Spigot end
|
||||||
|
|
||||||
private static boolean hasBiomesForStructureSet(StructureSet structureSet, BiomeSource biomeSource) {
|
private static boolean hasBiomesForStructureSet(StructureSet structureSet, BiomeSource biomeSource) {
|
||||||
Stream<Holder<Biome>> stream = structureSet.structures().stream().flatMap((structureset_a) -> {
|
Stream<Holder<Biome>> stream = structureSet.structures().stream().flatMap(structureEntry -> {
|
||||||
@@ -73,12 +166,13 @@
|
@@ -67,13 +_,14 @@
|
||||||
return stream.anyMatch(set::contains);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- private ChunkGeneratorStructureState(RandomState noiseConfig, BiomeSource biomeSource, long structureSeed, long concentricRingSeed, List<Holder<StructureSet>> structureSets) {
|
private ChunkGeneratorStructureState(
|
||||||
+ private ChunkGeneratorStructureState(RandomState noiseConfig, BiomeSource biomeSource, long structureSeed, long concentricRingSeed, List<Holder<StructureSet>> structureSets, SpigotWorldConfig conf) { // Paper - Add missing structure set seed configs
|
- RandomState randomState, BiomeSource biomeSource, long levelSeed, long cocentricRingsSeed, List<Holder<StructureSet>> possibleStructureSets
|
||||||
this.randomState = noiseConfig;
|
+ RandomState randomState, BiomeSource biomeSource, long levelSeed, long cocentricRingsSeed, List<Holder<StructureSet>> possibleStructureSets, org.spigotmc.SpigotWorldConfig conf // Paper - Add missing structure set seed configs
|
||||||
this.levelSeed = structureSeed;
|
) {
|
||||||
|
this.randomState = randomState;
|
||||||
|
this.levelSeed = levelSeed;
|
||||||
this.biomeSource = biomeSource;
|
this.biomeSource = biomeSource;
|
||||||
this.concentricRingsSeed = concentricRingSeed;
|
this.concentricRingsSeed = cocentricRingsSeed;
|
||||||
this.possibleStructureSets = structureSets;
|
this.possibleStructureSets = possibleStructureSets;
|
||||||
+ this.conf = conf; // Paper - Add missing structure set seed configs
|
+ this.conf = conf; // Paper - Add missing structure set seed configs
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Holder<StructureSet>> possibleStructureSets() {
|
public List<Holder<StructureSet>> possibleStructureSets() {
|
||||||
@@ -132,7 +226,13 @@
|
@@ -118,7 +_,13 @@
|
||||||
HolderSet<Biome> holderset = placement.preferredBiomes();
|
int spread = placement.spread();
|
||||||
RandomSource randomsource = RandomSource.create();
|
HolderSet<Biome> holderSet = placement.preferredBiomes();
|
||||||
|
RandomSource randomSource = RandomSource.create();
|
||||||
+ // Paper start - Add missing structure set seed configs
|
+ // Paper start - Add missing structure set seed configs
|
||||||
+ if (this.conf.strongholdSeed != null && structureSetEntry.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) {
|
+ if (this.conf.strongholdSeed != null && structureSet.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) {
|
||||||
+ randomsource.setSeed(this.conf.strongholdSeed);
|
+ randomSource.setSeed(this.conf.strongholdSeed);
|
||||||
+ } else {
|
+ } else {
|
||||||
+ // Paper end - Add missing structure set seed configs
|
+ // Paper end - Add missing structure set seed configs
|
||||||
randomsource.setSeed(this.concentricRingsSeed);
|
randomSource.setSeed(this.concentricRingsSeed);
|
||||||
+ } // Paper - Add missing structure set seed configs
|
+ } // Paper - Add missing structure set seed configs
|
||||||
double d0 = randomsource.nextDouble() * Math.PI * 2.0D;
|
double d = randomSource.nextDouble() * Math.PI * 2.0;
|
||||||
int l = 0;
|
int i = 0;
|
||||||
int i1 = 0;
|
int i1 = 0;
|
||||||
@@ -209,7 +309,7 @@
|
@@ -197,7 +_,7 @@
|
||||||
|
|
||||||
for (int l = centerChunkX - chunkCount; l <= centerChunkX + chunkCount; ++l) {
|
for (int i = x - range; i <= x + range; i++) {
|
||||||
for (int i1 = centerChunkZ - chunkCount; i1 <= centerChunkZ + chunkCount; ++i1) {
|
for (int i1 = z - range; i1 <= z + range; i1++) {
|
||||||
- if (structureplacement.isStructureChunk(this, l, i1)) {
|
- if (structurePlacement.isStructureChunk(this, i, i1)) {
|
||||||
+ if (structureplacement.isStructureChunk(this, l, i1, structureplacement instanceof KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs
|
+ if (structurePlacement.isStructureChunk(this, i, i1, structurePlacement instanceof KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/net/minecraft/world/level/chunk/DataLayer.java
|
--- a/net/minecraft/world/level/chunk/DataLayer.java
|
||||||
+++ b/net/minecraft/world/level/chunk/DataLayer.java
|
+++ b/net/minecraft/world/level/chunk/DataLayer.java
|
||||||
@@ -1,3 +1,4 @@
|
@@ -1,3 +_,4 @@
|
||||||
+// mc-dev import
|
+// mc-dev import
|
||||||
package net.minecraft.world.level.chunk;
|
package net.minecraft.world.level.chunk;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
--- a/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
||||||
+++ b/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
+++ b/net/minecraft/world/level/chunk/EmptyLevelChunk.java
|
||||||
@@ -25,6 +25,12 @@
|
@@ -25,6 +_,12 @@
|
||||||
public BlockState getBlockState(BlockPos pos) {
|
public BlockState getBlockState(BlockPos pos) {
|
||||||
return Blocks.VOID_AIR.defaultBlockState();
|
return Blocks.VOID_AIR.defaultBlockState();
|
||||||
}
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
--- a/net/minecraft/world/level/chunk/HashMapPalette.java
|
||||||
|
+++ b/net/minecraft/world/level/chunk/HashMapPalette.java
|
||||||
|
@@ -20,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMapPalette(IdMap<T> registry, int bits, PaletteResize<T> resizeHandler) {
|
||||||
|
- this(registry, bits, resizeHandler, CrudeIncrementalIntIdentityHashBiMap.create(1 << bits));
|
||||||
|
+ this(registry, bits, resizeHandler, CrudeIncrementalIntIdentityHashBiMap.create((1 << bits) + 1)); // Paper - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashMapPalette(IdMap<T> registry, int bits, PaletteResize<T> resizeHandler, CrudeIncrementalIntIdentityHashBiMap<T> values) {
|
||||||
|
@@ -38,10 +_,16 @@
|
||||||
|
public int idFor(T state) {
|
||||||
|
int id = this.values.getId(state);
|
||||||
|
if (id == -1) {
|
||||||
|
- id = this.values.add(state);
|
||||||
|
- if (id >= 1 << this.bits) {
|
||||||
|
+ // Paper start - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize
|
||||||
|
+ // We use size() instead of the result from add(K)
|
||||||
|
+ // This avoids adding another object unnecessarily
|
||||||
|
+ // Without this change, + 2 would be required in the constructor
|
||||||
|
+ if (this.values.size() >= 1 << this.bits) {
|
||||||
|
id = this.resizeHandler.onResize(this.bits + 1, state);
|
||||||
|
+ } else {
|
||||||
|
+ id = this.values.add(state);
|
||||||
|
}
|
||||||
|
+ // Paper end - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
|
@ -0,0 +1,307 @@
|
||||||
|
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
@@ -76,7 +_,7 @@
|
||||||
|
};
|
||||||
|
private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel = Maps.newHashMap();
|
||||||
|
public boolean loaded;
|
||||||
|
- public final Level level;
|
||||||
|
+ public final ServerLevel level; // CraftBukkit - type
|
||||||
|
@Nullable
|
||||||
|
private Supplier<FullChunkStatus> fullStatus;
|
||||||
|
@Nullable
|
||||||
|
@@ -85,6 +_,14 @@
|
||||||
|
private final LevelChunkTicks<Block> blockTicks;
|
||||||
|
private final LevelChunkTicks<Fluid> fluidTicks;
|
||||||
|
private LevelChunk.UnsavedListener unsavedListener = chunkPos -> {};
|
||||||
|
+ // CraftBukkit start
|
||||||
|
+ public boolean mustNotSave;
|
||||||
|
+ public boolean needsDecoration;
|
||||||
|
+ // CraftBukkit end
|
||||||
|
+
|
||||||
|
+ // Paper start
|
||||||
|
+ boolean loadedTicketLevel;
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
public LevelChunk(Level level, ChunkPos pos) {
|
||||||
|
this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null);
|
||||||
|
@@ -102,7 +_,7 @@
|
||||||
|
@Nullable BlendingData blendingData
|
||||||
|
) {
|
||||||
|
super(pos, data, level, level.registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData);
|
||||||
|
- this.level = level;
|
||||||
|
+ this.level = (net.minecraft.server.level.ServerLevel) level; // CraftBukkit - type
|
||||||
|
this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
for (Heightmap.Types types : Heightmap.Types.values()) {
|
||||||
|
@@ -154,6 +_,10 @@
|
||||||
|
this.skyLightSources = chunk.skyLightSources;
|
||||||
|
this.setLightCorrect(chunk.isLightCorrect());
|
||||||
|
this.markUnsaved();
|
||||||
|
+ this.needsDecoration = true; // CraftBukkit
|
||||||
|
+ // CraftBukkit start
|
||||||
|
+ this.persistentDataContainer = chunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading.
|
||||||
|
+ // CraftBukkit end
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnsavedListener(LevelChunk.UnsavedListener unsavedListener) {
|
||||||
|
@@ -162,6 +_,12 @@
|
||||||
|
unsavedListener.setUnsaved(this.chunkPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ // Paper start
|
||||||
|
+ @Override
|
||||||
|
+ public long getInhabitedTime() {
|
||||||
|
+ return this.level.paperConfig().chunks.fixedChunkInhabitedTime < 0 ? super.getInhabitedTime() : this.level.paperConfig().chunks.fixedChunkInhabitedTime;
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markUnsaved() {
|
||||||
|
@@ -195,8 +_,25 @@
|
||||||
|
: super.getListenerRegistry(sectionY);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start - Perf: Reduce instructions and provide final method
|
||||||
|
+ public BlockState getBlockState(final int x, final int y, final int z) {
|
||||||
|
+ return this.getBlockStateFinal(x, y, z);
|
||||||
|
+ }
|
||||||
|
+ public BlockState getBlockStateFinal(final int x, final int y, final int z) {
|
||||||
|
+ // Copied and modified from below
|
||||||
|
+ final int sectionIndex = this.getSectionIndex(y);
|
||||||
|
+ if (sectionIndex < 0 || sectionIndex >= this.sections.length
|
||||||
|
+ || this.sections[sectionIndex].nonEmptyBlockCount == 0) {
|
||||||
|
+ return Blocks.AIR.defaultBlockState();
|
||||||
|
+ }
|
||||||
|
+ return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15);
|
||||||
|
+ }
|
||||||
|
@Override
|
||||||
|
public BlockState getBlockState(BlockPos pos) {
|
||||||
|
+ if (true) {
|
||||||
|
+ return this.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
+ }
|
||||||
|
+ // Paper end - Perf: Reduce instructions and provide final method
|
||||||
|
int x = pos.getX();
|
||||||
|
int y = pos.getY();
|
||||||
|
int z = pos.getZ();
|
||||||
|
@@ -231,33 +_,54 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Paper start - If loaded util
|
||||||
|
+ @Override
|
||||||
|
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
|
||||||
|
+ return this.getFluidState(blockposition);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
|
||||||
|
+ return this.getBlockState(blockposition);
|
||||||
|
+ }
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public FluidState getFluidState(BlockPos pos) {
|
||||||
|
return this.getFluidState(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidState getFluidState(int x, int y, int z) {
|
||||||
|
- try {
|
||||||
|
+ // try { // Paper start - Perf: Optimise Chunk#getFluid
|
||||||
|
int sectionIndex = this.getSectionIndex(y);
|
||||||
|
if (sectionIndex >= 0 && sectionIndex < this.sections.length) {
|
||||||
|
LevelChunkSection levelChunkSection = this.sections[sectionIndex];
|
||||||
|
if (!levelChunkSection.hasOnlyAir()) {
|
||||||
|
- return levelChunkSection.getFluidState(x & 15, y & 15, z & 15);
|
||||||
|
+ return levelChunkSection.states.get((y & 15) << 8 | (z & 15) << 4 | x & 15).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Fluids.EMPTY.defaultFluidState();
|
||||||
|
+ /* // Paper - Perf: Optimise Chunk#getFluid
|
||||||
|
} catch (Throwable var7) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(var7, "Getting fluid state");
|
||||||
|
CrashReportCategory crashReportCategory = crashReport.addCategory("Block being got");
|
||||||
|
crashReportCategory.setDetail("Location", () -> CrashReportCategory.formatLocation(this, x, y, z));
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
|
+ */ // Paper - Perf: Optimise Chunk#getFluid
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving) {
|
||||||
|
+// CraftBukkit start
|
||||||
|
+ return this.setBlockState(pos, state, isMoving, true);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Nullable
|
||||||
|
+ public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving, boolean doPlace) {
|
||||||
|
+ // CraftBukkit end
|
||||||
|
int y = pos.getY();
|
||||||
|
LevelChunkSection section = this.getSection(this.getSectionIndex(y));
|
||||||
|
boolean hasOnlyAir = section.hasOnlyAir();
|
||||||
|
@@ -292,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasBlockEntity = blockState.hasBlockEntity();
|
||||||
|
- if (!this.level.isClientSide) {
|
||||||
|
+ if (!this.level.isClientSide && !this.level.isBlockPlaceCancelled) { // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent
|
||||||
|
blockState.onRemove(this.level, pos, state, isMoving);
|
||||||
|
} else if (!blockState.is(block) && hasBlockEntity) {
|
||||||
|
this.removeBlockEntity(pos);
|
||||||
|
@@ -301,7 +_,7 @@
|
||||||
|
if (!section.getBlockState(i, i1, i2).is(block)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
- if (!this.level.isClientSide) {
|
||||||
|
+ if (!this.level.isClientSide && doPlace && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled.
|
||||||
|
state.onPlace(this.level, pos, blockState, isMoving);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -355,7 +_,12 @@
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) {
|
||||||
|
- BlockEntity blockEntity = this.blockEntities.get(pos);
|
||||||
|
+ // CraftBukkit start
|
||||||
|
+ BlockEntity blockEntity = this.level.capturedTileEntities.get(pos);
|
||||||
|
+ if (blockEntity == null) {
|
||||||
|
+ blockEntity = this.blockEntities.get(pos);
|
||||||
|
+ }
|
||||||
|
+ // CraftBukkit end
|
||||||
|
if (blockEntity == null) {
|
||||||
|
CompoundTag compoundTag = this.pendingBlockEntities.remove(pos);
|
||||||
|
if (compoundTag != null) {
|
||||||
|
@@ -409,7 +_,13 @@
|
||||||
|
BlockPos blockPos = blockEntity.getBlockPos();
|
||||||
|
BlockState blockState = this.getBlockState(blockPos);
|
||||||
|
if (!blockState.hasBlockEntity()) {
|
||||||
|
- LOGGER.warn("Trying to set block entity {} at position {}, but state {} does not allow it", blockEntity, blockPos, blockState);
|
||||||
|
+ // Paper start - ServerExceptionEvent
|
||||||
|
+ com.destroystokyo.paper.exception.ServerInternalException e = new com.destroystokyo.paper.exception.ServerInternalException(
|
||||||
|
+ "Trying to set block entity %s at position %s, but state %s does not allow it".formatted(blockEntity, blockPos, blockState)
|
||||||
|
+ );
|
||||||
|
+ e.printStackTrace();
|
||||||
|
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(e);
|
||||||
|
+ // Paper end - ServerExceptionEvent
|
||||||
|
} else {
|
||||||
|
BlockState blockState1 = blockEntity.getBlockState();
|
||||||
|
if (blockState != blockState1) {
|
||||||
|
@@ -457,6 +_,11 @@
|
||||||
|
public void removeBlockEntity(BlockPos pos) {
|
||||||
|
if (this.isInLevel()) {
|
||||||
|
BlockEntity blockEntity = this.blockEntities.remove(pos);
|
||||||
|
+ // CraftBukkit start - SPIGOT-5561: Also remove from pending map
|
||||||
|
+ if (!this.pendingBlockEntities.isEmpty()) {
|
||||||
|
+ this.pendingBlockEntities.remove(pos);
|
||||||
|
+ }
|
||||||
|
+ // CraftBukkit end
|
||||||
|
if (blockEntity != null) {
|
||||||
|
if (this.level instanceof ServerLevel serverLevel) {
|
||||||
|
this.removeGameEventListener(blockEntity, serverLevel);
|
||||||
|
@@ -499,6 +_,65 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // CraftBukkit start
|
||||||
|
+ public void loadCallback() {
|
||||||
|
+ // Paper start
|
||||||
|
+ this.loadedTicketLevel = true;
|
||||||
|
+ // Paper end
|
||||||
|
+ org.bukkit.Server server = this.level.getCraftServer();
|
||||||
|
+ this.level.getChunkSource().addLoadedChunk(this); // Paper
|
||||||
|
+ if (server != null) {
|
||||||
|
+ /*
|
||||||
|
+ * If it's a new world, the first few chunks are generated inside
|
||||||
|
+ * the World constructor. We can't reliably alter that, so we have
|
||||||
|
+ * no way of creating a CraftWorld/CraftServer at that point.
|
||||||
|
+ */
|
||||||
|
+ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
|
||||||
|
+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration));
|
||||||
|
+
|
||||||
|
+ if (this.needsDecoration) {
|
||||||
|
+ this.needsDecoration = false;
|
||||||
|
+ java.util.Random random = new java.util.Random();
|
||||||
|
+ random.setSeed(this.level.getSeed());
|
||||||
|
+ long xRand = random.nextLong() / 2L * 2L + 1L;
|
||||||
|
+ long zRand = random.nextLong() / 2L * 2L + 1L;
|
||||||
|
+ random.setSeed((long) this.chunkPos.x * xRand + (long) this.chunkPos.z * zRand ^ this.level.getSeed());
|
||||||
|
+
|
||||||
|
+ org.bukkit.World world = this.level.getWorld();
|
||||||
|
+ if (world != null) {
|
||||||
|
+ this.level.populating = true;
|
||||||
|
+ try {
|
||||||
|
+ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) {
|
||||||
|
+ populator.populate(world, random, bukkitChunk);
|
||||||
|
+ }
|
||||||
|
+ } finally {
|
||||||
|
+ this.level.populating = false;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void unloadCallback() {
|
||||||
|
+ org.bukkit.Server server = this.level.getCraftServer();
|
||||||
|
+ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
|
||||||
|
+ org.bukkit.event.world.ChunkUnloadEvent unloadEvent = new org.bukkit.event.world.ChunkUnloadEvent(bukkitChunk, this.isUnsaved());
|
||||||
|
+ server.getPluginManager().callEvent(unloadEvent);
|
||||||
|
+ // note: saving can be prevented, but not forced if no saving is actually required
|
||||||
|
+ this.mustNotSave = !unloadEvent.isSaveChunk();
|
||||||
|
+ this.level.getChunkSource().removeLoadedChunk(this); // Paper
|
||||||
|
+ // Paper start
|
||||||
|
+ this.loadedTicketLevel = false;
|
||||||
|
+ // Paper end
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean isUnsaved() {
|
||||||
|
+ return super.isUnsaved() && !this.mustNotSave;
|
||||||
|
+ }
|
||||||
|
+ // CraftBukkit end
|
||||||
|
+
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@@ -711,23 +_,25 @@
|
||||||
|
if (this.blockEntity.getType().isValid(blockState)) {
|
||||||
|
this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity);
|
||||||
|
this.loggedInvalidBlockState = false;
|
||||||
|
- } else if (!this.loggedInvalidBlockState) {
|
||||||
|
- this.loggedInvalidBlockState = true;
|
||||||
|
- LevelChunk.LOGGER
|
||||||
|
- .warn(
|
||||||
|
- "Block entity {} @ {} state {} invalid for ticking:",
|
||||||
|
- LogUtils.defer(this::getType),
|
||||||
|
- LogUtils.defer(this::getPos),
|
||||||
|
- blockState
|
||||||
|
- );
|
||||||
|
- }
|
||||||
|
+ // Paper start - Remove the Block Entity if it's invalid
|
||||||
|
+ } else {
|
||||||
|
+ LevelChunk.this.removeBlockEntity(this.getPos());
|
||||||
|
+ if (!this.loggedInvalidBlockState) {
|
||||||
|
+ this.loggedInvalidBlockState = true;
|
||||||
|
+ LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), blockState});
|
||||||
|
+ }
|
||||||
|
+ // Paper end - Remove the Block Entity if it's invalid
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
|
||||||
|
profilerFiller.pop();
|
||||||
|
} catch (Throwable var5) {
|
||||||
|
- CrashReport crashReport = CrashReport.forThrowable(var5, "Ticking block entity");
|
||||||
|
- CrashReportCategory crashReportCategory = crashReport.addCategory("Block entity being ticked");
|
||||||
|
- this.blockEntity.fillCrashReportCategory(crashReportCategory);
|
||||||
|
- throw new ReportedException(crashReport);
|
||||||
|
+ // Paper start - Prevent block entity and entity crashes
|
||||||
|
+ final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
|
||||||
|
+ net.minecraft.server.MinecraftServer.LOGGER.error(msg, var5);
|
||||||
|
+ net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, var5))); // Paper - ServerExceptionEvent
|
||||||
|
+ LevelChunk.this.removeBlockEntity(this.getPos());
|
||||||
|
+ // Paper end - Prevent block entity and entity crashes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
|
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||||
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||||
@@ -19,11 +19,11 @@
|
@@ -18,11 +_,11 @@
|
||||||
public static final int SECTION_HEIGHT = 16;
|
public static final int SECTION_HEIGHT = 16;
|
||||||
public static final int SECTION_SIZE = 4096;
|
public static final int SECTION_SIZE = 4096;
|
||||||
public static final int BIOME_CONTAINER_BITS = 2;
|
public static final int BIOME_CONTAINER_BITS = 2;
|
||||||
|
@ -14,38 +14,33 @@
|
||||||
|
|
||||||
private LevelChunkSection(LevelChunkSection section) {
|
private LevelChunkSection(LevelChunkSection section) {
|
||||||
this.nonEmptyBlockCount = section.nonEmptyBlockCount;
|
this.nonEmptyBlockCount = section.nonEmptyBlockCount;
|
||||||
@@ -33,9 +33,9 @@
|
@@ -32,7 +_,7 @@
|
||||||
this.biomes = section.biomes.copy();
|
this.biomes = section.biomes.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
- public LevelChunkSection(PalettedContainer<BlockState> blockStateContainer, PalettedContainerRO<Holder<Biome>> biomeContainer) {
|
- public LevelChunkSection(PalettedContainer<BlockState> states, PalettedContainerRO<Holder<Biome>> biomes) {
|
||||||
- this.states = blockStateContainer;
|
+ public LevelChunkSection(PalettedContainer<BlockState> states, PalettedContainer<Holder<Biome>> biomes) { // CraftBukkit - read/write
|
||||||
- this.biomes = biomeContainer;
|
this.states = states;
|
||||||
+ public LevelChunkSection(PalettedContainer<BlockState> datapaletteblock, PalettedContainer<Holder<Biome>> palettedcontainerro) { // CraftBukkit - read/write
|
this.biomes = biomes;
|
||||||
+ this.states = datapaletteblock;
|
|
||||||
+ this.biomes = palettedcontainerro;
|
|
||||||
this.recalcBlockCounts();
|
this.recalcBlockCounts();
|
||||||
}
|
@@ -48,7 +_,7 @@
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FluidState getFluidState(int x, int y, int z) {
|
public FluidState getFluidState(int x, int y, int z) {
|
||||||
- return ((BlockState) this.states.get(x, y, z)).getFluidState();
|
- return this.states.get(x, y, z).getFluidState();
|
||||||
+ return this.states.get(x, y, z).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid; diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid.
|
+ return this.states.get(x, y, z).getFluidState(); // Paper - Perf: Optimise Chunk#getFluid; diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid.
|
||||||
}
|
}
|
||||||
|
|
||||||
public void acquire() {
|
public void acquire() {
|
||||||
@@ -196,6 +196,12 @@
|
@@ -185,6 +_,11 @@
|
||||||
return (Holder) this.biomes.get(x, y, z);
|
public Holder<Biome> getNoiseBiome(int x, int y, int z) {
|
||||||
|
return this.biomes.get(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ // CraftBukkit start
|
+ // CraftBukkit start
|
||||||
+ public void setBiome(int i, int j, int k, Holder<Biome> biome) {
|
+ public void setBiome(int i, int j, int k, Holder<Biome> biome) {
|
||||||
+ this.biomes.set(i, j, k, biome);
|
+ this.biomes.set(i, j, k, biome);
|
||||||
+ }
|
+ }
|
||||||
+ // CraftBukkit end
|
+ // CraftBukkit end
|
||||||
+
|
|
||||||
public void fillBiomesFromNoise(BiomeResolver biomeSupplier, Climate.Sampler sampler, int x, int y, int z) {
|
public void fillBiomesFromNoise(BiomeResolver biomeResolver, Climate.Sampler climateSampler, int x, int y, int z) {
|
||||||
PalettedContainer<Holder<Biome>> datapaletteblock = this.biomes.recreate();
|
PalettedContainer<Holder<Biome>> palettedContainer = this.biomes.recreate();
|
||||||
boolean flag = true;
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||||
|
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||||
|
@@ -30,14 +_,14 @@
|
||||||
|
public final IdMap<T> registry;
|
||||||
|
private volatile PalettedContainer.Data<T> data;
|
||||||
|
private final PalettedContainer.Strategy strategy;
|
||||||
|
- private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer");
|
||||||
|
+ //private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused
|
||||||
|
|
||||||
|
public void acquire() {
|
||||||
|
- this.threadingDetector.checkAndLock();
|
||||||
|
+ // this.threadingDetector.checkAndLock(); // Paper - disable this - use proper synchronization
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
- this.threadingDetector.checkAndUnlock();
|
||||||
|
+ // this.threadingDetector.checkAndUnlock(); // Paper - disable this - use proper synchronization
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value) {
|
||||||
|
@@ -99,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
- public int onResize(int bits, T objectAdded) {
|
||||||
|
+ public synchronized int onResize(int bits, T objectAdded) { // Paper - synchronize
|
||||||
|
PalettedContainer.Data<T> data = this.data;
|
||||||
|
PalettedContainer.Data<T> data1 = this.createOrReuseData(data, bits);
|
||||||
|
data1.copyFrom(data.palette, data.storage);
|
||||||
|
@@ -107,7 +_,7 @@
|
||||||
|
return data1.palette.idFor(objectAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
- public T getAndSet(int x, int y, int z, T state) {
|
||||||
|
+ public synchronized T getAndSet(int x, int y, int z, T state) { // Paper - synchronize
|
||||||
|
this.acquire();
|
||||||
|
|
||||||
|
Object var5;
|
||||||
|
@@ -130,7 +_,7 @@
|
||||||
|
return this.data.palette.valueFor(andSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void set(int x, int y, int z, T state) {
|
||||||
|
+ public synchronized void set(int x, int y, int z, T state) { // Paper - synchronize
|
||||||
|
this.acquire();
|
||||||
|
|
||||||
|
try {
|
||||||
|
@@ -163,7 +_,7 @@
|
||||||
|
set.forEach(id -> consumer.accept(palette.valueFor(id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void read(FriendlyByteBuf buffer) {
|
||||||
|
+ public synchronized void read(FriendlyByteBuf buffer) { // Paper - synchronize
|
||||||
|
this.acquire();
|
||||||
|
|
||||||
|
try {
|
||||||
|
@@ -178,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
- public void write(FriendlyByteBuf buffer) {
|
||||||
|
+ public synchronized void write(FriendlyByteBuf buffer) { // Paper - synchronize
|
||||||
|
this.acquire();
|
||||||
|
|
||||||
|
try {
|
||||||
|
@@ -226,7 +_,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
- public PalettedContainerRO.PackedData<T> pack(IdMap<T> registry, PalettedContainer.Strategy strategy) {
|
||||||
|
+ public synchronized PalettedContainerRO.PackedData<T> pack(IdMap<T> registry, PalettedContainer.Strategy strategy) { // Paper - synchronize
|
||||||
|
this.acquire();
|
||||||
|
|
||||||
|
PalettedContainerRO.PackedData var12;
|
|
@ -1,11 +1,9 @@
|
||||||
--- a/net/minecraft/world/level/chunk/ProtoChunk.java
|
--- a/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||||
+++ b/net/minecraft/world/level/chunk/ProtoChunk.java
|
+++ b/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||||
@@ -81,7 +81,19 @@
|
@@ -85,6 +_,18 @@
|
||||||
@Override
|
return new ChunkAccess.PackedTicks(this.blockTicks.pack(gametime), this.fluidTicks.pack(gametime));
|
||||||
public ChunkAccess.PackedTicks getTicksForSerialization(long time) {
|
}
|
||||||
return new ChunkAccess.PackedTicks(this.blockTicks.pack(time), this.fluidTicks.pack(time));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // Paper start - If loaded util
|
+ // Paper start - If loaded util
|
||||||
+ @Override
|
+ @Override
|
||||||
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
|
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
|
||||||
|
@ -15,8 +13,9 @@
|
||||||
+ @Override
|
+ @Override
|
||||||
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
|
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
|
||||||
+ return this.getBlockState(blockposition);
|
+ return this.getBlockState(blockposition);
|
||||||
}
|
+ }
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
|
+
|
||||||
@Override
|
@Override
|
||||||
public BlockState getBlockState(BlockPos pos) {
|
public BlockState getBlockState(BlockPos pos) {
|
||||||
|
int y = pos.getY();
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/net/minecraft/world/level/chunk/UpgradeData.java
|
--- a/net/minecraft/world/level/chunk/UpgradeData.java
|
||||||
+++ b/net/minecraft/world/level/chunk/UpgradeData.java
|
+++ b/net/minecraft/world/level/chunk/UpgradeData.java
|
||||||
@@ -113,12 +113,36 @@
|
@@ -113,6 +_,24 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,26 +22,25 @@
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - filter out relocated neighbour ticks
|
+ // Paper end - filter out relocated neighbour ticks
|
||||||
+
|
|
||||||
public void upgrade(LevelChunk chunk) {
|
public void upgrade(LevelChunk chunk) {
|
||||||
this.upgradeInside(chunk);
|
this.upgradeInside(chunk);
|
||||||
|
|
||||||
for (Direction8 direction8 : DIRECTIONS) {
|
@@ -120,6 +_,10 @@
|
||||||
upgradeSides(chunk, direction8);
|
upgradeSides(chunk, direction8);
|
||||||
}
|
}
|
||||||
+
|
|
||||||
+ // Paper start - filter out relocated neighbour ticks
|
+ // Paper start - filter out relocated neighbour ticks
|
||||||
+ filterTickList(chunk.locX, chunk.locZ, this.neighborBlockTicks);
|
+ filterTickList(chunk.locX, chunk.locZ, this.neighborBlockTicks);
|
||||||
+ filterTickList(chunk.locX, chunk.locZ, this.neighborFluidTicks);
|
+ filterTickList(chunk.locX, chunk.locZ, this.neighborFluidTicks);
|
||||||
+ // Paper end - filter out relocated neighbour ticks
|
+ // Paper end - filter out relocated neighbour ticks
|
||||||
|
|
||||||
Level level = chunk.getLevel();
|
Level level = chunk.getLevel();
|
||||||
this.neighborBlockTicks.forEach(tick -> {
|
this.neighborBlockTicks.forEach(blockTicker -> {
|
||||||
@@ -129,6 +153,7 @@
|
Block block = blockTicker.type() == Blocks.AIR ? level.getBlockState(blockTicker.pos()).getBlock() : blockTicker.type();
|
||||||
Fluid fluid = tick.type() == Fluids.EMPTY ? level.getFluidState(tick.pos()).getType() : tick.type();
|
@@ -129,6 +_,7 @@
|
||||||
level.scheduleTick(tick.pos(), fluid, tick.delay(), tick.priority());
|
Fluid fluid = fluidTicker.type() == Fluids.EMPTY ? level.getFluidState(fluidTicker.pos()).getType() : fluidTicker.type();
|
||||||
|
level.scheduleTick(fluidTicker.pos(), fluid, fluidTicker.delay(), fluidTicker.priority());
|
||||||
});
|
});
|
||||||
+ UpgradeData.BlockFixers.values(); // Paper - force the class init so that we don't access CHUNKY_FIXERS before all BlockFixers are initialised
|
+ UpgradeData.BlockFixers.values(); // Paper - force the class init so that we don't access CHUNKY_FIXERS before all BlockFixers are initialised
|
||||||
CHUNKY_FIXERS.forEach(logic -> logic.processChunk(level));
|
CHUNKY_FIXERS.forEach(fixers -> fixers.processChunk(level));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,224 +0,0 @@
|
||||||
--- a/net/minecraft/world/level/chunk/ChunkGenerator.java
|
|
||||||
+++ b/net/minecraft/world/level/chunk/ChunkGenerator.java
|
|
||||||
@@ -108,8 +108,8 @@
|
|
||||||
|
|
||||||
protected abstract MapCodec<? extends ChunkGenerator> codec();
|
|
||||||
|
|
||||||
- public ChunkGeneratorStructureState createState(HolderLookup<StructureSet> structureSetRegistry, RandomState noiseConfig, long seed) {
|
|
||||||
- return ChunkGeneratorStructureState.createForNormal(noiseConfig, seed, this.biomeSource, structureSetRegistry);
|
|
||||||
+ public ChunkGeneratorStructureState createState(HolderLookup<StructureSet> holderlookup, RandomState randomstate, long i, org.spigotmc.SpigotWorldConfig conf) { // Spigot
|
|
||||||
+ return ChunkGeneratorStructureState.createForNormal(randomstate, i, this.biomeSource, holderlookup, conf); // Spigot
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> getTypeNameForDataFixer() {
|
|
||||||
@@ -127,6 +127,24 @@
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Pair<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel world, HolderSet<Structure> structures, BlockPos center, int radius, boolean skipReferencedStructures) {
|
|
||||||
+ // Paper start - StructuresLocateEvent
|
|
||||||
+ final org.bukkit.World bukkitWorld = world.getWorld();
|
|
||||||
+ final org.bukkit.Location origin = io.papermc.paper.util.MCUtil.toLocation(world, center);
|
|
||||||
+ final List<org.bukkit.generator.structure.Structure> apiStructures = structures.stream().map(Holder::value).map(nms -> org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(nms)).toList();
|
|
||||||
+ if (!apiStructures.isEmpty()) {
|
|
||||||
+ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, radius, skipReferencedStructures);
|
|
||||||
+ if (!event.callEvent()) {
|
|
||||||
+ return null;
|
|
||||||
+ }
|
|
||||||
+ if (event.getResult() != null) {
|
|
||||||
+ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), world.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(event.getResult().structure())));
|
|
||||||
+ }
|
|
||||||
+ center = io.papermc.paper.util.MCUtil.toBlockPosition(event.getOrigin());
|
|
||||||
+ radius = event.getRadius();
|
|
||||||
+ skipReferencedStructures = event.shouldFindUnexplored();
|
|
||||||
+ structures = HolderSet.direct(api -> world.registryAccess().lookupOrThrow(Registries.STRUCTURE).wrapAsHolder(org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraft(api)), event.getStructures());
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
ChunkGeneratorStructureState chunkgeneratorstructurestate = world.getChunkSource().getGeneratorState();
|
|
||||||
Map<StructurePlacement, Set<Holder<Structure>>> map = new Object2ObjectArrayMap();
|
|
||||||
Iterator iterator = structures.iterator();
|
|
||||||
@@ -223,6 +241,7 @@
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
ChunkPos chunkcoordintpair = (ChunkPos) iterator.next();
|
|
||||||
+ if (!world.paperConfig().environment.locateStructuresOutsideWorldBorder && !world.getWorldBorder().isChunkInBounds(chunkcoordintpair.x, chunkcoordintpair.z)) { continue; } // Paper - Bound treasure maps to world border
|
|
||||||
|
|
||||||
blockposition_mutableblockposition.set(SectionPos.sectionToBlockCoord(chunkcoordintpair.x, 8), 32, SectionPos.sectionToBlockCoord(chunkcoordintpair.z, 8));
|
|
||||||
double d1 = blockposition_mutableblockposition.distSqr(center);
|
|
||||||
@@ -247,12 +266,15 @@
|
|
||||||
int i1 = placement.spacing();
|
|
||||||
|
|
||||||
for (int j1 = -radius; j1 <= radius; ++j1) {
|
|
||||||
- boolean flag1 = j1 == -radius || j1 == radius;
|
|
||||||
+ // Paper start - Perf: iterate over border chunks instead of entire square chunk area
|
|
||||||
+ boolean flag1 = j1 == -radius || j1 == radius; final boolean onBorderAlongZAxis = flag1; // Paper - OBFHELPER
|
|
||||||
|
|
||||||
- for (int k1 = -radius; k1 <= radius; ++k1) {
|
|
||||||
- boolean flag2 = k1 == -radius || k1 == radius;
|
|
||||||
+ for (int k1 = -radius; k1 <= radius; k1 += onBorderAlongZAxis ? 1 : radius * 2) {
|
|
||||||
+ // boolean flag2 = k1 == -radius || k1 == radius;
|
|
||||||
|
|
||||||
- if (flag1 || flag2) {
|
|
||||||
+ // if (flag1 || flag2) {
|
|
||||||
+ if (true) {
|
|
||||||
+ // Paper end - Perf: iterate over border chunks instead of entire square chunk area
|
|
||||||
int l1 = centerChunkX + i1 * j1;
|
|
||||||
int i2 = centerChunkZ + i1 * k1;
|
|
||||||
ChunkPos chunkcoordintpair = placement.getPotentialStructureChunk(seed, l1, i2);
|
|
||||||
@@ -312,29 +334,29 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- public void applyBiomeDecoration(WorldGenLevel world, ChunkAccess chunk, StructureManager structureAccessor) {
|
|
||||||
- ChunkPos chunkcoordintpair = chunk.getPos();
|
|
||||||
+ public void addVanillaDecorations(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { // CraftBukkit
|
|
||||||
+ ChunkPos chunkcoordintpair = ichunkaccess.getPos();
|
|
||||||
|
|
||||||
if (!SharedConstants.debugVoidTerrain(chunkcoordintpair)) {
|
|
||||||
- SectionPos sectionposition = SectionPos.of(chunkcoordintpair, world.getMinSectionY());
|
|
||||||
+ SectionPos sectionposition = SectionPos.of(chunkcoordintpair, generatoraccessseed.getMinSectionY());
|
|
||||||
BlockPos blockposition = sectionposition.origin();
|
|
||||||
- Registry<Structure> iregistry = world.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
|
||||||
+ Registry<Structure> iregistry = generatoraccessseed.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
|
||||||
Map<Integer, List<Structure>> map = (Map) iregistry.stream().collect(Collectors.groupingBy((structure) -> {
|
|
||||||
return structure.step().ordinal();
|
|
||||||
}));
|
|
||||||
List<FeatureSorter.StepFeatureData> list = (List) this.featuresPerStep.get();
|
|
||||||
WorldgenRandom seededrandom = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
|
||||||
- long i = seededrandom.setDecorationSeed(world.getSeed(), blockposition.getX(), blockposition.getZ());
|
|
||||||
+ long i = seededrandom.setDecorationSeed(generatoraccessseed.getSeed(), blockposition.getX(), blockposition.getZ());
|
|
||||||
Set<Holder<Biome>> set = new ObjectArraySet();
|
|
||||||
|
|
||||||
ChunkPos.rangeClosed(sectionposition.chunk(), 1).forEach((chunkcoordintpair1) -> {
|
|
||||||
- ChunkAccess ichunkaccess1 = world.getChunk(chunkcoordintpair1.x, chunkcoordintpair1.z);
|
|
||||||
+ ChunkAccess ichunkaccess1 = generatoraccessseed.getChunk(chunkcoordintpair1.x, chunkcoordintpair1.z);
|
|
||||||
LevelChunkSection[] achunksection = ichunkaccess1.getSections();
|
|
||||||
int j = achunksection.length;
|
|
||||||
|
|
||||||
for (int k = 0; k < j; ++k) {
|
|
||||||
LevelChunkSection chunksection = achunksection[k];
|
|
||||||
- PalettedContainerRO palettedcontainerro = chunksection.getBiomes();
|
|
||||||
+ PalettedContainerRO<Holder<Biome>> palettedcontainerro = chunksection.getBiomes(); // CraftBukkit - decompile error
|
|
||||||
|
|
||||||
Objects.requireNonNull(set);
|
|
||||||
palettedcontainerro.getAll(set::add);
|
|
||||||
@@ -345,7 +367,7 @@
|
|
||||||
int j = list.size();
|
|
||||||
|
|
||||||
try {
|
|
||||||
- Registry<PlacedFeature> iregistry1 = world.registryAccess().lookupOrThrow(Registries.PLACED_FEATURE);
|
|
||||||
+ Registry<PlacedFeature> iregistry1 = generatoraccessseed.registryAccess().lookupOrThrow(Registries.PLACED_FEATURE);
|
|
||||||
int k = Math.max(GenerationStep.Decoration.values().length, j);
|
|
||||||
|
|
||||||
for (int l = 0; l < k; ++l) {
|
|
||||||
@@ -353,7 +375,7 @@
|
|
||||||
Iterator iterator;
|
|
||||||
CrashReportCategory crashreportsystemdetails;
|
|
||||||
|
|
||||||
- if (structureAccessor.shouldGenerateStructures()) {
|
|
||||||
+ if (structuremanager.shouldGenerateStructures()) {
|
|
||||||
List<Structure> list1 = (List) map.getOrDefault(l, Collections.emptyList());
|
|
||||||
|
|
||||||
for (iterator = list1.iterator(); iterator.hasNext(); ++i1) {
|
|
||||||
@@ -368,9 +390,9 @@
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
- world.setCurrentlyGenerating(supplier);
|
|
||||||
- structureAccessor.startsForStructure(sectionposition, structure).forEach((structurestart) -> {
|
|
||||||
- structurestart.placeInChunk(world, structureAccessor, this, seededrandom, ChunkGenerator.getWritableArea(chunk), chunkcoordintpair);
|
|
||||||
+ generatoraccessseed.setCurrentlyGenerating(supplier);
|
|
||||||
+ structuremanager.startsForStructure(sectionposition, structure).forEach((structurestart) -> {
|
|
||||||
+ structurestart.placeInChunk(generatoraccessseed, structuremanager, this, seededrandom, ChunkGenerator.getWritableArea(ichunkaccess), chunkcoordintpair);
|
|
||||||
});
|
|
||||||
} catch (Exception exception) {
|
|
||||||
CrashReport crashreport = CrashReport.forThrowable(exception, "Feature placement");
|
|
||||||
@@ -418,11 +440,18 @@
|
|
||||||
return (String) optional.orElseGet(placedfeature::toString);
|
|
||||||
};
|
|
||||||
|
|
||||||
- seededrandom.setFeatureSeed(i, l1, l);
|
|
||||||
+ // Paper start - Configurable feature seeds; change populationSeed used in random
|
|
||||||
+ long featurePopulationSeed = i;
|
|
||||||
+ final long configFeatureSeed = generatoraccessseed.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(placedfeature.feature());
|
|
||||||
+ if (configFeatureSeed != -1) {
|
|
||||||
+ featurePopulationSeed = seededrandom.setDecorationSeed(configFeatureSeed, blockposition.getX(), blockposition.getZ()); // See seededrandom.setDecorationSeed from above
|
|
||||||
+ }
|
|
||||||
+ seededrandom.setFeatureSeed(featurePopulationSeed, l1, l);
|
|
||||||
+ // Paper end - Configurable feature seeds
|
|
||||||
|
|
||||||
try {
|
|
||||||
- world.setCurrentlyGenerating(supplier1);
|
|
||||||
- placedfeature.placeWithBiomeCheck(world, this, seededrandom, blockposition);
|
|
||||||
+ generatoraccessseed.setCurrentlyGenerating(supplier1);
|
|
||||||
+ placedfeature.placeWithBiomeCheck(generatoraccessseed, this, seededrandom, blockposition);
|
|
||||||
} catch (Exception exception1) {
|
|
||||||
CrashReport crashreport1 = CrashReport.forThrowable(exception1, "Feature placement");
|
|
||||||
|
|
||||||
@@ -435,15 +464,42 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- world.setCurrentlyGenerating((Supplier) null);
|
|
||||||
+ generatoraccessseed.setCurrentlyGenerating((Supplier) null);
|
|
||||||
} catch (Exception exception2) {
|
|
||||||
CrashReport crashreport2 = CrashReport.forThrowable(exception2, "Biome decoration");
|
|
||||||
|
|
||||||
crashreport2.addCategory("Generation").setDetail("CenterX", (Object) chunkcoordintpair.x).setDetail("CenterZ", (Object) chunkcoordintpair.z).setDetail("Decoration Seed", (Object) i);
|
|
||||||
throw new ReportedException(crashreport2);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // CraftBukkit start
|
|
||||||
+ public void applyBiomeDecoration(WorldGenLevel world, ChunkAccess chunk, StructureManager structureAccessor) {
|
|
||||||
+ this.applyBiomeDecoration(world, chunk, structureAccessor, true);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
|
||||||
+ if (vanilla) {
|
|
||||||
+ this.addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ org.bukkit.World world = generatoraccessseed.getMinecraftWorld().getWorld();
|
|
||||||
+ // only call when a populator is present (prevents unnecessary entity conversion)
|
|
||||||
+ if (!world.getPopulators().isEmpty()) {
|
|
||||||
+ org.bukkit.craftbukkit.generator.CraftLimitedRegion limitedRegion = new org.bukkit.craftbukkit.generator.CraftLimitedRegion(generatoraccessseed, ichunkaccess.getPos());
|
|
||||||
+ int x = ichunkaccess.getPos().x;
|
|
||||||
+ int z = ichunkaccess.getPos().z;
|
|
||||||
+ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) {
|
|
||||||
+ WorldgenRandom seededrandom = new WorldgenRandom(new net.minecraft.world.level.levelgen.LegacyRandomSource(generatoraccessseed.getSeed()));
|
|
||||||
+ seededrandom.setDecorationSeed(generatoraccessseed.getSeed(), x, z);
|
|
||||||
+ populator.populate(world, new org.bukkit.craftbukkit.util.RandomSourceWrapper.RandomWrapper(seededrandom), x, z, limitedRegion);
|
|
||||||
}
|
|
||||||
+ limitedRegion.saveEntities();
|
|
||||||
+ limitedRegion.breakLink();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ // CraftBukkit end
|
|
||||||
|
|
||||||
private static BoundingBox getWritableArea(ChunkAccess chunk) {
|
|
||||||
ChunkPos chunkcoordintpair = chunk.getPos();
|
|
||||||
@@ -521,7 +577,7 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (structureplacement.isStructureChunk(placementCalculator, chunkcoordintpair.x, chunkcoordintpair.z)) {
|
|
||||||
+ if (structureplacement.isStructureChunk(placementCalculator, chunkcoordintpair.x, chunkcoordintpair.z, structureplacement instanceof net.minecraft.world.level.chunk.ChunkGeneratorStructureState.KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs
|
|
||||||
if (list.size() == 1) {
|
|
||||||
this.tryGenerateStructure((StructureSet.StructureSelectionEntry) list.get(0), structureAccessor, registryManager, randomstate, structureTemplateManager, placementCalculator.getLevelSeed(), chunk, chunkcoordintpair, sectionposition, dimension);
|
|
||||||
} else {
|
|
||||||
@@ -582,6 +638,14 @@
|
|
||||||
StructureStart structurestart = structure.generate(weightedEntry.structure(), dimension, dynamicRegistryManager, this, this.biomeSource, noiseConfig, structureManager, seed, pos, j, chunk, predicate);
|
|
||||||
|
|
||||||
if (structurestart.isValid()) {
|
|
||||||
+ // CraftBukkit start
|
|
||||||
+ BoundingBox box = structurestart.getBoundingBox();
|
|
||||||
+ org.bukkit.event.world.AsyncStructureSpawnEvent event = new org.bukkit.event.world.AsyncStructureSpawnEvent(structureAccessor.level.getMinecraftWorld().getWorld(), org.bukkit.craftbukkit.generator.structure.CraftStructure.minecraftToBukkit(structure), new org.bukkit.util.BoundingBox(box.minX(), box.minY(), box.minZ(), box.maxX(), box.maxY(), box.maxZ()), pos.x, pos.z);
|
|
||||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
|
|
||||||
+ if (event.isCancelled()) {
|
|
||||||
+ return true;
|
|
||||||
+ }
|
|
||||||
+ // CraftBukkit end
|
|
||||||
structureAccessor.setStartForStructure(sectionPos, structure, structurestart, chunk);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
|
@ -1,30 +0,0 @@
|
||||||
--- a/net/minecraft/world/level/chunk/HashMapPalette.java
|
|
||||||
+++ b/net/minecraft/world/level/chunk/HashMapPalette.java
|
|
||||||
@@ -20,7 +20,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMapPalette(IdMap<T> idList, int indexBits, PaletteResize<T> listener) {
|
|
||||||
- this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create(1 << indexBits));
|
|
||||||
+ this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create((1 << indexBits) + 1)); // Paper - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private HashMapPalette(IdMap<T> idList, int indexBits, PaletteResize<T> listener, CrudeIncrementalIntIdentityHashBiMap<T> map) {
|
|
||||||
@@ -38,10 +38,16 @@
|
|
||||||
public int idFor(T object) {
|
|
||||||
int i = this.values.getId(object);
|
|
||||||
if (i == -1) {
|
|
||||||
- i = this.values.add(object);
|
|
||||||
- if (i >= 1 << this.bits) {
|
|
||||||
+ // Paper start - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize
|
|
||||||
+ // We use size() instead of the result from add(K)
|
|
||||||
+ // This avoids adding another object unnecessarily
|
|
||||||
+ // Without this change, + 2 would be required in the constructor
|
|
||||||
+ if (this.values.size() >= 1 << this.bits) {
|
|
||||||
i = this.resizeHandler.onResize(this.bits + 1, object);
|
|
||||||
+ } else {
|
|
||||||
+ i = this.values.add(object);
|
|
||||||
}
|
|
||||||
+ // Paper end - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
|
@ -1,409 +0,0 @@
|
||||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
|
||||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
|
||||||
@@ -79,7 +79,7 @@
|
|
||||||
};
|
|
||||||
private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel;
|
|
||||||
public boolean loaded;
|
|
||||||
- public final Level level;
|
|
||||||
+ public final ServerLevel level; // CraftBukkit - type
|
|
||||||
@Nullable
|
|
||||||
private Supplier<FullChunkStatus> fullStatus;
|
|
||||||
@Nullable
|
|
||||||
@@ -98,7 +98,7 @@
|
|
||||||
this.tickersInLevel = Maps.newHashMap();
|
|
||||||
this.unsavedListener = (chunkcoordintpair1) -> {
|
|
||||||
};
|
|
||||||
- this.level = world;
|
|
||||||
+ this.level = (ServerLevel) world; // CraftBukkit - type
|
|
||||||
this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap();
|
|
||||||
Heightmap.Types[] aheightmap_type = Heightmap.Types.values();
|
|
||||||
int j = aheightmap_type.length;
|
|
||||||
@@ -116,6 +116,15 @@
|
|
||||||
this.fluidTicks = fluidTickScheduler;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // CraftBukkit start
|
|
||||||
+ public boolean mustNotSave;
|
|
||||||
+ public boolean needsDecoration;
|
|
||||||
+ // CraftBukkit end
|
|
||||||
+
|
|
||||||
+ // Paper start
|
|
||||||
+ boolean loadedTicketLevel;
|
|
||||||
+ // Paper end
|
|
||||||
+
|
|
||||||
public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor entityLoader) {
|
|
||||||
this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), entityLoader, protoChunk.getBlendingData());
|
|
||||||
if (!Collections.disjoint(protoChunk.pendingBlockEntities.keySet(), protoChunk.blockEntities.keySet())) {
|
|
||||||
@@ -151,6 +160,10 @@
|
|
||||||
this.skyLightSources = protoChunk.skyLightSources;
|
|
||||||
this.setLightCorrect(protoChunk.isLightCorrect());
|
|
||||||
this.markUnsaved();
|
|
||||||
+ this.needsDecoration = true; // CraftBukkit
|
|
||||||
+ // CraftBukkit start
|
|
||||||
+ this.persistentDataContainer = protoChunk.persistentDataContainer; // SPIGOT-6814: copy PDC to account for 1.17 to 1.18 chunk upgrading.
|
|
||||||
+ // CraftBukkit end
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUnsavedListener(LevelChunk.UnsavedListener unsavedListener) {
|
|
||||||
@@ -187,7 +200,14 @@
|
|
||||||
return new ChunkAccess.PackedTicks(this.blockTicks.pack(time), this.fluidTicks.pack(time));
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Paper start
|
|
||||||
@Override
|
|
||||||
+ public long getInhabitedTime() {
|
|
||||||
+ return this.level.paperConfig().chunks.fixedChunkInhabitedTime < 0 ? super.getInhabitedTime() : this.level.paperConfig().chunks.fixedChunkInhabitedTime;
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
public GameEventListenerRegistry getListenerRegistry(int ySectionCoord) {
|
|
||||||
Level world = this.level;
|
|
||||||
|
|
||||||
@@ -200,8 +220,25 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Paper start - Perf: Reduce instructions and provide final method
|
|
||||||
+ public BlockState getBlockState(final int x, final int y, final int z) {
|
|
||||||
+ return this.getBlockStateFinal(x, y, z);
|
|
||||||
+ }
|
|
||||||
+ public BlockState getBlockStateFinal(final int x, final int y, final int z) {
|
|
||||||
+ // Copied and modified from below
|
|
||||||
+ final int sectionIndex = this.getSectionIndex(y);
|
|
||||||
+ if (sectionIndex < 0 || sectionIndex >= this.sections.length
|
|
||||||
+ || this.sections[sectionIndex].nonEmptyBlockCount == 0) {
|
|
||||||
+ return Blocks.AIR.defaultBlockState();
|
|
||||||
+ }
|
|
||||||
+ return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15);
|
|
||||||
+ }
|
|
||||||
@Override
|
|
||||||
public BlockState getBlockState(BlockPos pos) {
|
|
||||||
+ if (true) {
|
|
||||||
+ return this.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
|
|
||||||
+ }
|
|
||||||
+ // Paper end - Perf: Reduce instructions and provide final method
|
|
||||||
int i = pos.getX();
|
|
||||||
int j = pos.getY();
|
|
||||||
int k = pos.getZ();
|
|
||||||
@@ -243,24 +280,38 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Paper start - If loaded util
|
|
||||||
@Override
|
|
||||||
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
|
|
||||||
+ return this.getFluidState(blockposition);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
|
|
||||||
+ return this.getBlockState(blockposition);
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
public FluidState getFluidState(BlockPos pos) {
|
|
||||||
return this.getFluidState(pos.getX(), pos.getY(), pos.getZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
public FluidState getFluidState(int x, int y, int z) {
|
|
||||||
- try {
|
|
||||||
- int l = this.getSectionIndex(y);
|
|
||||||
+ // Paper start - Perf: Optimise Chunk#getFluid
|
|
||||||
+ // try { // Remove try catch
|
|
||||||
+ int index = this.getSectionIndex(y);
|
|
||||||
+ if (index >= 0 && index < this.sections.length) {
|
|
||||||
+ LevelChunkSection chunksection = this.sections[index];
|
|
||||||
|
|
||||||
- if (l >= 0 && l < this.sections.length) {
|
|
||||||
- LevelChunkSection chunksection = this.sections[l];
|
|
||||||
-
|
|
||||||
if (!chunksection.hasOnlyAir()) {
|
|
||||||
- return chunksection.getFluidState(x & 15, y & 15, z & 15);
|
|
||||||
+ return chunksection.states.get((y & 15) << 8 | (z & 15) << 4 | x & 15).getFluidState();
|
|
||||||
+ // Paper end - Perf: Optimise Chunk#getFluid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Fluids.EMPTY.defaultFluidState();
|
|
||||||
+ /* // Paper - Perf: Optimise Chunk#getFluid
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state");
|
|
||||||
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got");
|
|
||||||
@@ -270,80 +321,89 @@
|
|
||||||
});
|
|
||||||
throw new ReportedException(crashreport);
|
|
||||||
}
|
|
||||||
+ */ // Paper - Perf: Optimise Chunk#getFluid
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // CraftBukkit start
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public BlockState setBlockState(BlockPos pos, BlockState state, boolean moved) {
|
|
||||||
- int i = pos.getY();
|
|
||||||
+ return this.setBlockState(pos, state, moved, true);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Nullable
|
|
||||||
+ public BlockState setBlockState(BlockPos blockposition, BlockState iblockdata, boolean flag, boolean doPlace) {
|
|
||||||
+ // CraftBukkit end
|
|
||||||
+ int i = blockposition.getY();
|
|
||||||
LevelChunkSection chunksection = this.getSection(this.getSectionIndex(i));
|
|
||||||
boolean flag1 = chunksection.hasOnlyAir();
|
|
||||||
|
|
||||||
- if (flag1 && state.isAir()) {
|
|
||||||
+ if (flag1 && iblockdata.isAir()) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
- int j = pos.getX() & 15;
|
|
||||||
+ int j = blockposition.getX() & 15;
|
|
||||||
int k = i & 15;
|
|
||||||
- int l = pos.getZ() & 15;
|
|
||||||
- BlockState iblockdata1 = chunksection.setBlockState(j, k, l, state);
|
|
||||||
+ int l = blockposition.getZ() & 15;
|
|
||||||
+ BlockState iblockdata1 = chunksection.setBlockState(j, k, l, iblockdata);
|
|
||||||
|
|
||||||
- if (iblockdata1 == state) {
|
|
||||||
+ if (iblockdata1 == iblockdata) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
- Block block = state.getBlock();
|
|
||||||
+ Block block = iblockdata.getBlock();
|
|
||||||
|
|
||||||
- ((Heightmap) this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING)).update(j, i, l, state);
|
|
||||||
- ((Heightmap) this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES)).update(j, i, l, state);
|
|
||||||
- ((Heightmap) this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR)).update(j, i, l, state);
|
|
||||||
- ((Heightmap) this.heightmaps.get(Heightmap.Types.WORLD_SURFACE)).update(j, i, l, state);
|
|
||||||
+ ((Heightmap) this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING)).update(j, i, l, iblockdata);
|
|
||||||
+ ((Heightmap) this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES)).update(j, i, l, iblockdata);
|
|
||||||
+ ((Heightmap) this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR)).update(j, i, l, iblockdata);
|
|
||||||
+ ((Heightmap) this.heightmaps.get(Heightmap.Types.WORLD_SURFACE)).update(j, i, l, iblockdata);
|
|
||||||
boolean flag2 = chunksection.hasOnlyAir();
|
|
||||||
|
|
||||||
if (flag1 != flag2) {
|
|
||||||
- this.level.getChunkSource().getLightEngine().updateSectionStatus(pos, flag2);
|
|
||||||
+ this.level.getChunkSource().getLightEngine().updateSectionStatus(blockposition, flag2);
|
|
||||||
this.level.getChunkSource().onSectionEmptinessChanged(this.chunkPos.x, SectionPos.blockToSectionCoord(i), this.chunkPos.z, flag2);
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (LightEngine.hasDifferentLightProperties(iblockdata1, state)) {
|
|
||||||
+ if (LightEngine.hasDifferentLightProperties(iblockdata1, iblockdata)) {
|
|
||||||
ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
||||||
|
|
||||||
gameprofilerfiller.push("updateSkyLightSources");
|
|
||||||
this.skyLightSources.update(this, j, i, l);
|
|
||||||
gameprofilerfiller.popPush("queueCheckLight");
|
|
||||||
- this.level.getChunkSource().getLightEngine().checkBlock(pos);
|
|
||||||
+ this.level.getChunkSource().getLightEngine().checkBlock(blockposition);
|
|
||||||
gameprofilerfiller.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean flag3 = iblockdata1.hasBlockEntity();
|
|
||||||
|
|
||||||
- if (!this.level.isClientSide) {
|
|
||||||
- iblockdata1.onRemove(this.level, pos, state, moved);
|
|
||||||
+ if (!this.level.isClientSide && !this.level.isBlockPlaceCancelled) { // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent
|
|
||||||
+ iblockdata1.onRemove(this.level, blockposition, iblockdata, flag);
|
|
||||||
} else if (!iblockdata1.is(block) && flag3) {
|
|
||||||
- this.removeBlockEntity(pos);
|
|
||||||
+ this.removeBlockEntity(blockposition);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!chunksection.getBlockState(j, k, l).is(block)) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
- if (!this.level.isClientSide) {
|
|
||||||
- state.onPlace(this.level, pos, iblockdata1, moved);
|
|
||||||
+ // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled.
|
|
||||||
+ if (!this.level.isClientSide && doPlace && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) {
|
|
||||||
+ iblockdata.onPlace(this.level, blockposition, iblockdata1, flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (state.hasBlockEntity()) {
|
|
||||||
- BlockEntity tileentity = this.getBlockEntity(pos, LevelChunk.EntityCreationType.CHECK);
|
|
||||||
+ if (iblockdata.hasBlockEntity()) {
|
|
||||||
+ BlockEntity tileentity = this.getBlockEntity(blockposition, LevelChunk.EntityCreationType.CHECK);
|
|
||||||
|
|
||||||
- if (tileentity != null && !tileentity.isValidBlockState(state)) {
|
|
||||||
- LevelChunk.LOGGER.warn("Found mismatched block entity @ {}: type = {}, state = {}", new Object[]{pos, tileentity.getType().builtInRegistryHolder().key().location(), state});
|
|
||||||
- this.removeBlockEntity(pos);
|
|
||||||
+ if (tileentity != null && !tileentity.isValidBlockState(iblockdata)) {
|
|
||||||
+ LevelChunk.LOGGER.warn("Found mismatched block entity @ {}: type = {}, state = {}", new Object[]{blockposition, tileentity.getType().builtInRegistryHolder().key().location(), iblockdata});
|
|
||||||
+ this.removeBlockEntity(blockposition);
|
|
||||||
tileentity = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tileentity == null) {
|
|
||||||
- tileentity = ((EntityBlock) block).newBlockEntity(pos, state);
|
|
||||||
+ tileentity = ((EntityBlock) block).newBlockEntity(blockposition, iblockdata);
|
|
||||||
if (tileentity != null) {
|
|
||||||
this.addAndRegisterBlockEntity(tileentity);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
- tileentity.setBlockState(state);
|
|
||||||
+ tileentity.setBlockState(iblockdata);
|
|
||||||
this.updateBlockEntityTicker(tileentity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -375,7 +435,12 @@
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) {
|
|
||||||
- BlockEntity tileentity = (BlockEntity) this.blockEntities.get(pos);
|
|
||||||
+ // CraftBukkit start
|
|
||||||
+ BlockEntity tileentity = this.level.capturedTileEntities.get(pos);
|
|
||||||
+ if (tileentity == null) {
|
|
||||||
+ tileentity = (BlockEntity) this.blockEntities.get(pos);
|
|
||||||
+ }
|
|
||||||
+ // CraftBukkit end
|
|
||||||
|
|
||||||
if (tileentity == null) {
|
|
||||||
CompoundTag nbttagcompound = (CompoundTag) this.pendingBlockEntities.remove(pos);
|
|
||||||
@@ -446,7 +511,13 @@
|
|
||||||
BlockState iblockdata = this.getBlockState(blockposition);
|
|
||||||
|
|
||||||
if (!iblockdata.hasBlockEntity()) {
|
|
||||||
- LevelChunk.LOGGER.warn("Trying to set block entity {} at position {}, but state {} does not allow it", new Object[]{blockEntity, blockposition, iblockdata});
|
|
||||||
+ // Paper start - ServerExceptionEvent
|
|
||||||
+ com.destroystokyo.paper.exception.ServerInternalException e = new com.destroystokyo.paper.exception.ServerInternalException(
|
|
||||||
+ "Trying to set block entity %s at position %s, but state %s does not allow it".formatted(blockEntity, blockposition, iblockdata)
|
|
||||||
+ );
|
|
||||||
+ e.printStackTrace();
|
|
||||||
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(e);
|
|
||||||
+ // Paper end - ServerExceptionEvent
|
|
||||||
} else {
|
|
||||||
BlockState iblockdata1 = blockEntity.getBlockState();
|
|
||||||
|
|
||||||
@@ -500,6 +571,12 @@
|
|
||||||
if (this.isInLevel()) {
|
|
||||||
BlockEntity tileentity = (BlockEntity) this.blockEntities.remove(pos);
|
|
||||||
|
|
||||||
+ // CraftBukkit start - SPIGOT-5561: Also remove from pending map
|
|
||||||
+ if (!this.pendingBlockEntities.isEmpty()) {
|
|
||||||
+ this.pendingBlockEntities.remove(pos);
|
|
||||||
+ }
|
|
||||||
+ // CraftBukkit end
|
|
||||||
+
|
|
||||||
if (tileentity != null) {
|
|
||||||
Level world = this.level;
|
|
||||||
|
|
||||||
@@ -553,6 +630,65 @@
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // CraftBukkit start
|
|
||||||
+ public void loadCallback() {
|
|
||||||
+ // Paper start
|
|
||||||
+ this.loadedTicketLevel = true;
|
|
||||||
+ // Paper end
|
|
||||||
+ org.bukkit.Server server = this.level.getCraftServer();
|
|
||||||
+ this.level.getChunkSource().addLoadedChunk(this); // Paper
|
|
||||||
+ if (server != null) {
|
|
||||||
+ /*
|
|
||||||
+ * If it's a new world, the first few chunks are generated inside
|
|
||||||
+ * the World constructor. We can't reliably alter that, so we have
|
|
||||||
+ * no way of creating a CraftWorld/CraftServer at that point.
|
|
||||||
+ */
|
|
||||||
+ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
|
|
||||||
+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration));
|
|
||||||
+
|
|
||||||
+ if (this.needsDecoration) {
|
|
||||||
+ this.needsDecoration = false;
|
|
||||||
+ java.util.Random random = new java.util.Random();
|
|
||||||
+ random.setSeed(this.level.getSeed());
|
|
||||||
+ long xRand = random.nextLong() / 2L * 2L + 1L;
|
|
||||||
+ long zRand = random.nextLong() / 2L * 2L + 1L;
|
|
||||||
+ random.setSeed((long) this.chunkPos.x * xRand + (long) this.chunkPos.z * zRand ^ this.level.getSeed());
|
|
||||||
+
|
|
||||||
+ org.bukkit.World world = this.level.getWorld();
|
|
||||||
+ if (world != null) {
|
|
||||||
+ this.level.populating = true;
|
|
||||||
+ try {
|
|
||||||
+ for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) {
|
|
||||||
+ populator.populate(world, random, bukkitChunk);
|
|
||||||
+ }
|
|
||||||
+ } finally {
|
|
||||||
+ this.level.populating = false;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk));
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public void unloadCallback() {
|
|
||||||
+ org.bukkit.Server server = this.level.getCraftServer();
|
|
||||||
+ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this);
|
|
||||||
+ org.bukkit.event.world.ChunkUnloadEvent unloadEvent = new org.bukkit.event.world.ChunkUnloadEvent(bukkitChunk, this.isUnsaved());
|
|
||||||
+ server.getPluginManager().callEvent(unloadEvent);
|
|
||||||
+ // note: saving can be prevented, but not forced if no saving is actually required
|
|
||||||
+ this.mustNotSave = !unloadEvent.isSaveChunk();
|
|
||||||
+ this.level.getChunkSource().removeLoadedChunk(this); // Paper
|
|
||||||
+ // Paper start
|
|
||||||
+ this.loadedTicketLevel = false;
|
|
||||||
+ // Paper end
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean isUnsaved() {
|
|
||||||
+ return super.isUnsaved() && !this.mustNotSave;
|
|
||||||
+ }
|
|
||||||
+ // CraftBukkit end
|
|
||||||
+
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -750,7 +886,7 @@
|
|
||||||
|
|
||||||
private <T extends BlockEntity> void updateBlockEntityTicker(T blockEntity) {
|
|
||||||
BlockState iblockdata = blockEntity.getBlockState();
|
|
||||||
- BlockEntityTicker<T> blockentityticker = iblockdata.getTicker(this.level, blockEntity.getType());
|
|
||||||
+ BlockEntityTicker<T> blockentityticker = iblockdata.getTicker(this.level, (BlockEntityType<T>) blockEntity.getType()); // CraftBukkit - decompile error
|
|
||||||
|
|
||||||
if (blockentityticker == null) {
|
|
||||||
this.removeBlockEntityTicker(blockEntity.getBlockPos());
|
|
||||||
@@ -841,7 +977,7 @@
|
|
||||||
private boolean loggedInvalidBlockState;
|
|
||||||
|
|
||||||
BoundTickingBlockEntity(final BlockEntity tileentity, final BlockEntityTicker blockentityticker) {
|
|
||||||
- this.blockEntity = tileentity;
|
|
||||||
+ this.blockEntity = (T) tileentity; // CraftBukkit - decompile error
|
|
||||||
this.ticker = blockentityticker;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -860,18 +996,25 @@
|
|
||||||
if (this.blockEntity.getType().isValid(iblockdata)) {
|
|
||||||
this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), iblockdata, this.blockEntity);
|
|
||||||
this.loggedInvalidBlockState = false;
|
|
||||||
- } else if (!this.loggedInvalidBlockState) {
|
|
||||||
- this.loggedInvalidBlockState = true;
|
|
||||||
- LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata});
|
|
||||||
+ // Paper start - Remove the Block Entity if it's invalid
|
|
||||||
+ } else {
|
|
||||||
+ LevelChunk.this.removeBlockEntity(this.getPos());
|
|
||||||
+ if (!this.loggedInvalidBlockState) {
|
|
||||||
+ this.loggedInvalidBlockState = true;
|
|
||||||
+ LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata});
|
|
||||||
+ }
|
|
||||||
+ // Paper end - Remove the Block Entity if it's invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
gameprofilerfiller.pop();
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking block entity");
|
|
||||||
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block entity being ticked");
|
|
||||||
-
|
|
||||||
- this.blockEntity.fillCrashReportCategory(crashreportsystemdetails);
|
|
||||||
- throw new ReportedException(crashreport);
|
|
||||||
+ // Paper start - Prevent block entity and entity crashes
|
|
||||||
+ final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
|
|
||||||
+ net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
|
|
||||||
+ net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); // Paper - ServerExceptionEvent
|
|
||||||
+ LevelChunk.this.removeBlockEntity(this.getPos());
|
|
||||||
+ // Paper end - Prevent block entity and entity crashes
|
|
||||||
+ // Spigot start
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
||||||
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
||||||
@@ -30,14 +30,14 @@
|
|
||||||
public final IdMap<T> registry;
|
|
||||||
private volatile PalettedContainer.Data<T> data;
|
|
||||||
private final PalettedContainer.Strategy strategy;
|
|
||||||
- private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer");
|
|
||||||
+ // private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused
|
|
||||||
|
|
||||||
public void acquire() {
|
|
||||||
- this.threadingDetector.checkAndLock();
|
|
||||||
+ // this.threadingDetector.checkAndLock(); // Paper - disable this - use proper synchronization
|
|
||||||
}
|
|
||||||
|
|
||||||
public void release() {
|
|
||||||
- this.threadingDetector.checkAndUnlock();
|
|
||||||
+ // this.threadingDetector.checkAndUnlock(); // Paper - disable this
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) {
|
|
||||||
@@ -110,7 +110,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
- public int onResize(int newBits, T object) {
|
|
||||||
+ public synchronized int onResize(int newBits, T object) { // Paper - synchronize
|
|
||||||
PalettedContainer.Data<T> data = this.data;
|
|
||||||
PalettedContainer.Data<T> data2 = this.createOrReuseData(data, newBits);
|
|
||||||
data2.copyFrom(data.palette, data.storage);
|
|
||||||
@@ -135,7 +135,7 @@
|
|
||||||
return this.getAndSet(this.strategy.getIndex(x, y, z), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
- private T getAndSet(int index, T value) {
|
|
||||||
+ private synchronized T getAndSet(int index, T value) { // Paper - synchronize
|
|
||||||
int i = this.data.palette.idFor(value);
|
|
||||||
int j = this.data.storage.getAndSet(index, i);
|
|
||||||
return this.data.palette.valueFor(j);
|
|
||||||
@@ -151,7 +151,7 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- private void set(int index, T value) {
|
|
||||||
+ private synchronized void set(int index, T value) { // Paper - synchronize
|
|
||||||
int i = this.data.palette.idFor(value);
|
|
||||||
this.data.storage.set(index, i);
|
|
||||||
}
|
|
||||||
@@ -174,7 +174,7 @@
|
|
||||||
intSet.forEach(id -> action.accept(palette.valueFor(id)));
|
|
||||||
}
|
|
||||||
|
|
||||||
- public void read(FriendlyByteBuf buf) {
|
|
||||||
+ public synchronized void read(FriendlyByteBuf buf) { // Paper - synchronize
|
|
||||||
this.acquire();
|
|
||||||
|
|
||||||
try {
|
|
||||||
@@ -189,7 +189,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
- public void write(FriendlyByteBuf buf) {
|
|
||||||
+ public synchronized void write(FriendlyByteBuf buf) { // Paper - synchronize
|
|
||||||
this.acquire();
|
|
||||||
|
|
||||||
try {
|
|
||||||
@@ -237,7 +237,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
- public PalettedContainerRO.PackedData<T> pack(IdMap<T> idList, PalettedContainer.Strategy paletteProvider) {
|
|
||||||
+ public synchronized PalettedContainerRO.PackedData<T> pack(IdMap<T> idList, PalettedContainer.Strategy paletteProvider) { // Paper - synchronize
|
|
||||||
this.acquire();
|
|
||||||
|
|
||||||
PalettedContainerRO.PackedData var12;
|
|
Loading…
Reference in a new issue