#937: Fixes related to unplaced BlockStates and the recent world generation changes.

* CraftBlockState#getWorldHandle() would previously run into a NPE when being invoked for a non-placed BlockState. It now returns null in this case.
* CraftChest#getInventory() would previously encounter this NPE when being called for a non-placed BlockState. It will now automatically forward the call to #getBlockInventory() when it is being called for either a non-placed BlockState, or during world generation.
* CraftStructureBlock#applyTo was able to run into a NPE when being called for non-placed BlockStates (this is for example called by #getSnapshotNBT()).
* Replaced all no-world-generation preconditions with a general 'ensureNoWorldGeneration' method.
* Removed a few superfluous #isPlaced() calls. If getWorldHandle() reutrns a World, this already implies that the BlockState is placed.

By: blablubbabc <lukas@wirsindwir.de>
This commit is contained in:
CraftBukkit/Spigot 2021-10-10 07:55:53 +11:00
parent 82e8261d70
commit 571ec764a6
9 changed files with 23 additions and 17 deletions

View file

@ -23,7 +23,7 @@ public class CraftBeacon extends CraftBlockEntityState<TileEntityBeacon> impleme
@Override
public Collection<LivingEntity> getEntitiesInRange() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't get entities during world generation");
ensureNoWorldGeneration();
TileEntity tileEntity = this.getTileEntityFromWorld();
if (tileEntity instanceof TileEntityBeacon) {

View file

@ -60,7 +60,7 @@ public class CraftBeehive extends CraftBlockEntityState<TileEntityBeehive> imple
@Override
public List<Bee> releaseEntities() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't release entities during world generation");
ensureNoWorldGeneration();
List<Bee> bees = new ArrayList<>();

View file

@ -57,20 +57,33 @@ public class CraftBlockState implements BlockState {
}
}
// Returns null if weakWorld is not available and the BlockState is not placed.
// If this returns a World instead of only a GeneratorAccess, this implies that this BlockState is placed.
public GeneratorAccess getWorldHandle() {
if (weakWorld == null) {
return world.getHandle();
return this.isPlaced() ? world.getHandle() : null;
}
GeneratorAccess access = weakWorld.get();
if (access == null) {
weakWorld = null;
return world.getHandle();
return this.isPlaced() ? world.getHandle() : null;
}
return access;
}
protected final boolean isWorldGeneration() {
GeneratorAccess generatorAccess = this.getWorldHandle();
return generatorAccess != null && !(generatorAccess instanceof World);
}
protected final void ensureNoWorldGeneration() {
if (isWorldGeneration()) {
throw new IllegalStateException("This operation is not supported during world generation!");
}
}
@Override
public World getWorld() {
requirePlaced();

View file

@ -37,10 +37,8 @@ public class CraftChest extends CraftLootable<TileEntityChest> implements Chest
@Override
public Inventory getInventory() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't get inventory during world generation, use getBlockInventory() instead");
CraftInventory inventory = (CraftInventory) this.getBlockInventory();
if (!isPlaced()) {
if (!isPlaced() || isWorldGeneration()) {
return inventory;
}

View file

@ -47,10 +47,8 @@ public class CraftDispenser extends CraftLootable<TileEntityDispenser> implement
@Override
public boolean dispense() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't dispense during world generation");
ensureNoWorldGeneration();
Block block = getBlock();
if (block.getType() == Material.DISPENSER) {
CraftWorld world = (CraftWorld) this.getWorld();
BlockDispenser dispense = (BlockDispenser) Blocks.DISPENSER;

View file

@ -34,10 +34,8 @@ public class CraftDropper extends CraftLootable<TileEntityDropper> implements Dr
@Override
public void drop() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't drop during world generation");
ensureNoWorldGeneration();
Block block = getBlock();
if (block.getType() == Material.DROPPER) {
CraftWorld world = (CraftWorld) this.getWorld();
BlockDropper drop = (BlockDropper) Blocks.DROPPER;

View file

@ -81,9 +81,8 @@ public class CraftJukebox extends CraftBlockEntityState<TileEntityJukeBox> imple
@Override
public boolean eject() {
Preconditions.checkState(getWorldHandle() instanceof net.minecraft.world.level.World, "Can't eject during world generation");
ensureNoWorldGeneration();
requirePlaced();
TileEntity tileEntity = this.getTileEntityFromWorld();
if (!(tileEntity instanceof TileEntityJukeBox)) return false;

View file

@ -42,7 +42,7 @@ public class CraftLectern extends CraftBlockEntityState<TileEntityLectern> imple
public boolean update(boolean force, boolean applyPhysics) {
boolean result = super.update(force, applyPhysics);
if (result && this.isPlaced() && this.getType() == Material.LECTERN && getWorldHandle() instanceof net.minecraft.world.level.World) {
if (result && this.getType() == Material.LECTERN && getWorldHandle() instanceof net.minecraft.world.level.World) {
BlockLectern.a(this.world.getHandle(), this.getPosition(), this.getHandle());
}

View file

@ -180,7 +180,7 @@ public class CraftStructureBlock extends CraftBlockEntityState<TileEntityStructu
// Ensure block type is correct
if (access instanceof net.minecraft.world.level.World) {
tileEntity.setUsageMode(tileEntity.getUsageMode());
} else {
} else if (access != null) {
// Custom handle during world generation
// From TileEntityStructure#setUsageMode(BlockPropertyStructureMode)
net.minecraft.world.level.block.state.IBlockData data = access.getType(this.getPosition());