minecraft-source/src/net/minecraft/world/level/block/state/BlockState.java

430 lines
17 KiB
Java

package net.minecraft.world.level.block.state;
import java.util.Arrays;
import net.minecraft.world.level.EmptyBlockGetter;
import java.util.Iterator;
import net.minecraft.resources.ResourceLocation;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.mojang.datafixers.util.Pair;
import java.util.Map;
import net.minecraft.core.Registry;
import com.mojang.datafixers.Dynamic;
import com.mojang.datafixers.types.DynamicOps;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.tags.Tag;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.item.BlockPlaceContext;
import net.minecraft.world.level.pathfinder.PathComputationType;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.InteractionHand;
import java.util.List;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.item.ItemStack;
import java.util.Random;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.material.MaterialColor;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.EntityType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.block.state.properties.Property;
import com.google.common.collect.ImmutableMap;
import javax.annotation.Nullable;
import net.minecraft.world.level.block.Block;
public class BlockState extends AbstractStateHolder<Block, BlockState> implements StateHolder<BlockState> {
@Nullable
private Cache cache;
private final int lightEmission;
private final boolean useShapeForLightOcclusion;
public BlockState(final Block bpe, final ImmutableMap<Property<?>, Comparable<?>> immutableMap) {
super(bpe, immutableMap);
this.lightEmission = bpe.getLightEmission(this);
this.useShapeForLightOcclusion = bpe.useShapeForLightOcclusion(this);
}
public void initCache() {
if (!this.getBlock().hasDynamicShape()) {
this.cache = new Cache(this);
}
}
public Block getBlock() {
return (Block)this.owner;
}
public Material getMaterial() {
return this.getBlock().getMaterial(this);
}
public boolean isValidSpawn(final BlockGetter bjd, final BlockPos fk, final EntityType<?> akr) {
return this.getBlock().isValidSpawn(this, bjd, fk, akr);
}
public boolean propagatesSkylightDown(final BlockGetter bjd, final BlockPos fk) {
if (this.cache != null) {
return this.cache.propagatesSkylightDown;
}
return this.getBlock().propagatesSkylightDown(this, bjd, fk);
}
public int getLightBlock(final BlockGetter bjd, final BlockPos fk) {
if (this.cache != null) {
return this.cache.lightBlock;
}
return this.getBlock().getLightBlock(this, bjd, fk);
}
public VoxelShape getFaceOcclusionShape(final BlockGetter bjd, final BlockPos fk, final Direction fp) {
if (this.cache != null && this.cache.occlusionShapes != null) {
return this.cache.occlusionShapes[fp.ordinal()];
}
return Shapes.getFaceShape(this.getOcclusionShape(bjd, fk), fp);
}
public boolean hasLargeCollisionShape() {
return this.cache == null || this.cache.largeCollisionShape;
}
public boolean useShapeForLightOcclusion() {
return this.useShapeForLightOcclusion;
}
public int getLightEmission() {
return this.lightEmission;
}
public boolean isAir() {
return this.getBlock().isAir(this);
}
public MaterialColor getMapColor(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().getMapColor(this, bjd, fk);
}
public BlockState rotate(final Rotation btr) {
return this.getBlock().rotate(this, btr);
}
public BlockState mirror(final Mirror bsr) {
return this.getBlock().mirror(this, bsr);
}
public RenderShape getRenderShape() {
return this.getBlock().getRenderShape(this);
}
public boolean emissiveRendering() {
return this.getBlock().emissiveRendering(this);
}
public float getShadeBrightness(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().getShadeBrightness(this, bjd, fk);
}
public boolean isRedstoneConductor(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().isRedstoneConductor(this, bjd, fk);
}
public boolean isSignalSource() {
return this.getBlock().isSignalSource(this);
}
public int getSignal(final BlockGetter bjd, final BlockPos fk, final Direction fp) {
return this.getBlock().getSignal(this, bjd, fk, fp);
}
public boolean hasAnalogOutputSignal() {
return this.getBlock().hasAnalogOutputSignal(this);
}
public int getAnalogOutputSignal(final Level bjt, final BlockPos fk) {
return this.getBlock().getAnalogOutputSignal(this, bjt, fk);
}
public float getDestroySpeed(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().getDestroySpeed(this, bjd, fk);
}
public float getDestroyProgress(final Player ayg, final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().getDestroyProgress(this, ayg, bjd, fk);
}
public int getDirectSignal(final BlockGetter bjd, final BlockPos fk, final Direction fp) {
return this.getBlock().getDirectSignal(this, bjd, fk, fp);
}
public PushReaction getPistonPushReaction() {
return this.getBlock().getPistonPushReaction(this);
}
public boolean isSolidRender(final BlockGetter bjd, final BlockPos fk) {
if (this.cache != null) {
return this.cache.solidRender;
}
return this.getBlock().isSolidRender(this, bjd, fk);
}
public boolean canOcclude() {
if (this.cache != null) {
return this.cache.canOcclude;
}
return this.getBlock().canOcclude(this);
}
public boolean skipRendering(final BlockState byg, final Direction fp) {
return this.getBlock().skipRendering(this, byg, fp);
}
public VoxelShape getShape(final BlockGetter bjd, final BlockPos fk) {
return this.getShape(bjd, fk, CollisionContext.empty());
}
public VoxelShape getShape(final BlockGetter bjd, final BlockPos fk, final CollisionContext cvn) {
return this.getBlock().getShape(this, bjd, fk, cvn);
}
public VoxelShape getCollisionShape(final BlockGetter bjd, final BlockPos fk) {
if (this.cache != null) {
return this.cache.collisionShape;
}
return this.getCollisionShape(bjd, fk, CollisionContext.empty());
}
public VoxelShape getCollisionShape(final BlockGetter bjd, final BlockPos fk, final CollisionContext cvn) {
return this.getBlock().getCollisionShape(this, bjd, fk, cvn);
}
public VoxelShape getOcclusionShape(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().getOcclusionShape(this, bjd, fk);
}
public VoxelShape getInteractionShape(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().getInteractionShape(this, bjd, fk);
}
public final boolean entityCanStandOn(final BlockGetter bjd, final BlockPos fk, final Entity akn) {
return Block.isFaceFull(this.getCollisionShape(bjd, fk, CollisionContext.of(akn)), Direction.UP);
}
public Vec3 getOffset(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().getOffset(this, bjd, fk);
}
public boolean triggerEvent(final Level bjt, final BlockPos fk, final int integer3, final int integer4) {
return this.getBlock().triggerEvent(this, bjt, fk, integer3, integer4);
}
public void neighborChanged(final Level bjt, final BlockPos fk2, final Block bpe, final BlockPos fk4, final boolean boolean5) {
this.getBlock().neighborChanged(this, bjt, fk2, bpe, fk4, boolean5);
}
public void updateNeighbourShapes(final LevelAccessor bju, final BlockPos fk, final int integer) {
this.getBlock().updateNeighbourShapes(this, bju, fk, integer);
}
public void updateIndirectNeighbourShapes(final LevelAccessor bju, final BlockPos fk, final int integer) {
this.getBlock().updateIndirectNeighbourShapes(this, bju, fk, integer);
}
public void onPlace(final Level bjt, final BlockPos fk, final BlockState byg, final boolean boolean4) {
this.getBlock().onPlace(this, bjt, fk, byg, boolean4);
}
public void onRemove(final Level bjt, final BlockPos fk, final BlockState byg, final boolean boolean4) {
this.getBlock().onRemove(this, bjt, fk, byg, boolean4);
}
public void tick(final ServerLevel xd, final BlockPos fk, final Random random) {
this.getBlock().tick(this, xd, fk, random);
}
public void randomTick(final ServerLevel xd, final BlockPos fk, final Random random) {
this.getBlock().randomTick(this, xd, fk, random);
}
public void entityInside(final Level bjt, final BlockPos fk, final Entity akn) {
this.getBlock().entityInside(this, bjt, fk, akn);
}
public void spawnAfterBreak(final Level bjt, final BlockPos fk, final ItemStack bek) {
this.getBlock().spawnAfterBreak(this, bjt, fk, bek);
}
public List<ItemStack> getDrops(final LootContext.Builder a) {
return this.getBlock().getDrops(this, a);
}
public InteractionResult use(final Level bjt, final Player ayg, final InteractionHand ajh, final BlockHitResult cvd) {
return this.getBlock().use(this, bjt, cvd.getBlockPos(), ayg, ajh, cvd);
}
public void attack(final Level bjt, final BlockPos fk, final Player ayg) {
this.getBlock().attack(this, bjt, fk, ayg);
}
public boolean isSuffocating(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().isSuffocating(this, bjd, fk);
}
public boolean isViewBlocking(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().isViewBlocking(this, bjd, fk);
}
public BlockState updateShape(final Direction fp, final BlockState byg, final LevelAccessor bju, final BlockPos fk4, final BlockPos fk5) {
return this.getBlock().updateShape(this, fp, byg, bju, fk4, fk5);
}
public boolean isPathfindable(final BlockGetter bjd, final BlockPos fk, final PathComputationType cqo) {
return this.getBlock().isPathfindable(this, bjd, fk, cqo);
}
public boolean canBeReplaced(final BlockPlaceContext bcn) {
return this.getBlock().canBeReplaced(this, bcn);
}
public boolean canBeReplaced(final Fluid cof) {
return this.getBlock().canBeReplaced(this, cof);
}
public boolean canSurvive(final LevelReader bjw, final BlockPos fk) {
return this.getBlock().canSurvive(this, bjw, fk);
}
public boolean hasPostProcess(final BlockGetter bjd, final BlockPos fk) {
return this.getBlock().hasPostProcess(this, bjd, fk);
}
@Nullable
public MenuProvider getMenuProvider(final Level bjt, final BlockPos fk) {
return this.getBlock().getMenuProvider(this, bjt, fk);
}
public boolean is(final Tag<Block> aaz) {
return this.getBlock().is(aaz);
}
public FluidState getFluidState() {
return this.getBlock().getFluidState(this);
}
public boolean isRandomlyTicking() {
return this.getBlock().isRandomlyTicking(this);
}
public long getSeed(final BlockPos fk) {
return this.getBlock().getSeed(this, fk);
}
public SoundType getSoundType() {
return this.getBlock().getSoundType(this);
}
public void onProjectileHit(final Level bjt, final BlockState byg, final BlockHitResult cvd, final Entity akn) {
this.getBlock().onProjectileHit(bjt, byg, cvd, akn);
}
public boolean isFaceSturdy(final BlockGetter bjd, final BlockPos fk, final Direction fp) {
if (this.cache != null) {
return this.cache.isFaceSturdy[fp.ordinal()];
}
return Block.isFaceSturdy(this, bjd, fk, fp);
}
public boolean isCollisionShapeFullBlock(final BlockGetter bjd, final BlockPos fk) {
if (this.cache != null) {
return this.cache.isCollisionShapeFullBlock;
}
return Block.isShapeFullBlock(this.getCollisionShape(bjd, fk));
}
public static <T> Dynamic<T> serialize(final DynamicOps<T> dynamicOps, final BlockState byg) {
final ImmutableMap<Property<?>, Comparable<?>> immutableMap3 = byg.getValues();
T object4;
if (immutableMap3.isEmpty()) {
object4 = (T)dynamicOps.createMap((Map)ImmutableMap.of(dynamicOps.createString("Name"), dynamicOps.createString(Registry.BLOCK.getKey(byg.getBlock()).toString())));
}
else {
object4 = (T)dynamicOps.createMap((Map)ImmutableMap.of(dynamicOps.createString("Name"), dynamicOps.createString(Registry.BLOCK.getKey(byg.getBlock()).toString()), dynamicOps.createString("Properties"), dynamicOps.createMap((Map)immutableMap3.entrySet().stream().map(entry -> Pair.of(dynamicOps.createString(entry.getKey().getName()), dynamicOps.createString(StateHolder.<Comparable>getName((Property<Comparable>)entry.getKey(), entry.getValue())))).collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)))));
}
return (Dynamic<T>)new Dynamic((DynamicOps)dynamicOps, object4);
}
public static <T> BlockState deserialize(final Dynamic<T> dynamic) {
final Block bpe2 = Registry.BLOCK.get(new ResourceLocation(dynamic.getElement("Name").<String>flatMap(dynamic.getOps()::getStringValue).orElse("minecraft:air")));
final Map<String, String> map3 = (Map<String, String>)dynamic.get("Properties").asMap(dynamic -> dynamic.asString(""), dynamic -> dynamic.asString(""));
BlockState byg4 = bpe2.defaultBlockState();
final StateDefinition<Block, BlockState> byh5 = bpe2.getStateDefinition();
for (final Map.Entry<String, String> entry7 : map3.entrySet()) {
final String string8 = entry7.getKey();
final Property<?> bzj9 = byh5.getProperty(string8);
if (bzj9 != null) {
byg4 = StateHolder.setValueHelper(byg4, bzj9, string8, dynamic.toString(), entry7.getValue());
}
}
return byg4;
}
static final class Cache {
private static final Direction[] DIRECTIONS;
private final boolean canOcclude;
private final boolean solidRender;
private final boolean propagatesSkylightDown;
private final int lightBlock;
private final VoxelShape[] occlusionShapes;
private final VoxelShape collisionShape;
private final boolean largeCollisionShape;
private final boolean[] isFaceSturdy;
private final boolean isCollisionShapeFullBlock;
private Cache(final BlockState byg) {
final Block bpe3 = byg.getBlock();
this.canOcclude = bpe3.canOcclude(byg);
this.solidRender = bpe3.isSolidRender(byg, EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
this.propagatesSkylightDown = bpe3.propagatesSkylightDown(byg, EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
this.lightBlock = bpe3.getLightBlock(byg, EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
if (!byg.canOcclude()) {
this.occlusionShapes = null;
}
else {
this.occlusionShapes = new VoxelShape[Cache.DIRECTIONS.length];
final VoxelShape cwc4 = bpe3.getOcclusionShape(byg, EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
for (final Direction fp8 : Cache.DIRECTIONS) {
this.occlusionShapes[fp8.ordinal()] = Shapes.getFaceShape(cwc4, fp8);
}
}
this.collisionShape = bpe3.getCollisionShape(byg, EmptyBlockGetter.INSTANCE, BlockPos.ZERO, CollisionContext.empty());
this.largeCollisionShape = Arrays.<Direction.Axis>stream(Direction.Axis.values()).anyMatch(a -> this.collisionShape.min(a) < 0.0 || this.collisionShape.max(a) > 1.0);
this.isFaceSturdy = new boolean[6];
for (final Direction fp9 : Cache.DIRECTIONS) {
this.isFaceSturdy[fp9.ordinal()] = Block.isFaceSturdy(byg, EmptyBlockGetter.INSTANCE, BlockPos.ZERO, fp9);
}
this.isCollisionShapeFullBlock = Block.isShapeFullBlock(byg.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO));
}
static {
DIRECTIONS = Direction.values();
}
}
}