430 lines
17 KiB
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();
|
|
}
|
|
}
|
|
}
|