minecraft-src/net/minecraft/world/level/chunk/UpgradeData.java
2025-07-04 03:45:38 +03:00

333 lines
11 KiB
Java

package net.minecraft.world.level.chunk;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import it.unimi.dsi.fastutil.ints.IntArrays;
import java.util.EnumSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction8;
import net.minecraft.core.SectionPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.ticks.SavedTick;
import org.slf4j.Logger;
public class UpgradeData {
private static final Logger LOGGER = LogUtils.getLogger();
public static final UpgradeData EMPTY = new UpgradeData(EmptyBlockGetter.INSTANCE);
private static final String TAG_INDICES = "Indices";
private static final Direction8[] DIRECTIONS = Direction8.values();
private static final Codec<List<SavedTick<Block>>> BLOCK_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.BLOCK.byNameCodec().orElse(Blocks.AIR)).listOf();
private static final Codec<List<SavedTick<Fluid>>> FLUID_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.FLUID.byNameCodec().orElse(Fluids.EMPTY)).listOf();
private final EnumSet<Direction8> sides = EnumSet.noneOf(Direction8.class);
private final List<SavedTick<Block>> neighborBlockTicks = Lists.<SavedTick<Block>>newArrayList();
private final List<SavedTick<Fluid>> neighborFluidTicks = Lists.<SavedTick<Fluid>>newArrayList();
private final int[][] index;
static final Map<Block, UpgradeData.BlockFixer> MAP = new IdentityHashMap();
static final Set<UpgradeData.BlockFixer> CHUNKY_FIXERS = Sets.<UpgradeData.BlockFixer>newHashSet();
private UpgradeData(LevelHeightAccessor level) {
this.index = new int[level.getSectionsCount()][];
}
public UpgradeData(CompoundTag tag, LevelHeightAccessor level) {
this(level);
tag.getCompound("Indices").ifPresent(compoundTag -> {
for (int ix = 0; ix < this.index.length; ix++) {
this.index[ix] = (int[])compoundTag.getIntArray(String.valueOf(ix)).orElse(null);
}
});
int i = tag.getIntOr("Sides", 0);
for (Direction8 direction8 : Direction8.values()) {
if ((i & 1 << direction8.ordinal()) != 0) {
this.sides.add(direction8);
}
}
tag.read("neighbor_block_ticks", BLOCK_TICKS_CODEC).ifPresent(this.neighborBlockTicks::addAll);
tag.read("neighbor_fluid_ticks", FLUID_TICKS_CODEC).ifPresent(this.neighborFluidTicks::addAll);
}
private UpgradeData(UpgradeData other) {
this.sides.addAll(other.sides);
this.neighborBlockTicks.addAll(other.neighborBlockTicks);
this.neighborFluidTicks.addAll(other.neighborFluidTicks);
this.index = new int[other.index.length][];
for (int i = 0; i < other.index.length; i++) {
int[] is = other.index[i];
this.index[i] = is != null ? IntArrays.copy(is) : null;
}
}
public void upgrade(LevelChunk chunk) {
this.upgradeInside(chunk);
for (Direction8 direction8 : DIRECTIONS) {
upgradeSides(chunk, direction8);
}
Level level = chunk.getLevel();
this.neighborBlockTicks.forEach(savedTick -> {
Block block = savedTick.type() == Blocks.AIR ? level.getBlockState(savedTick.pos()).getBlock() : (Block)savedTick.type();
level.scheduleTick(savedTick.pos(), block, savedTick.delay(), savedTick.priority());
});
this.neighborFluidTicks.forEach(savedTick -> {
Fluid fluid = savedTick.type() == Fluids.EMPTY ? level.getFluidState(savedTick.pos()).getType() : (Fluid)savedTick.type();
level.scheduleTick(savedTick.pos(), fluid, savedTick.delay(), savedTick.priority());
});
CHUNKY_FIXERS.forEach(blockFixer -> blockFixer.processChunk(level));
}
private static void upgradeSides(LevelChunk chunk, Direction8 side) {
Level level = chunk.getLevel();
if (chunk.getUpgradeData().sides.remove(side)) {
Set<Direction> set = side.getDirections();
int i = 0;
int j = 15;
boolean bl = set.contains(Direction.EAST);
boolean bl2 = set.contains(Direction.WEST);
boolean bl3 = set.contains(Direction.SOUTH);
boolean bl4 = set.contains(Direction.NORTH);
boolean bl5 = set.size() == 1;
ChunkPos chunkPos = chunk.getPos();
int k = chunkPos.getMinBlockX() + (!bl5 || !bl4 && !bl3 ? (bl2 ? 0 : 15) : 1);
int l = chunkPos.getMinBlockX() + (!bl5 || !bl4 && !bl3 ? (bl2 ? 0 : 15) : 14);
int m = chunkPos.getMinBlockZ() + (!bl5 || !bl && !bl2 ? (bl4 ? 0 : 15) : 1);
int n = chunkPos.getMinBlockZ() + (!bl5 || !bl && !bl2 ? (bl4 ? 0 : 15) : 14);
Direction[] directions = Direction.values();
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
for (BlockPos blockPos : BlockPos.betweenClosed(k, level.getMinY(), m, l, level.getMaxY(), n)) {
BlockState blockState = level.getBlockState(blockPos);
BlockState blockState2 = blockState;
for (Direction direction : directions) {
mutableBlockPos.setWithOffset(blockPos, direction);
blockState2 = updateState(blockState2, direction, level, blockPos, mutableBlockPos);
}
Block.updateOrDestroy(blockState, blockState2, level, blockPos, 18);
}
}
}
private static BlockState updateState(BlockState state, Direction direction, LevelAccessor level, BlockPos pos, BlockPos offsetPos) {
return ((UpgradeData.BlockFixer)MAP.getOrDefault(state.getBlock(), UpgradeData.BlockFixers.DEFAULT))
.updateShape(state, direction, level.getBlockState(offsetPos), level, pos, offsetPos);
}
private void upgradeInside(LevelChunk chunk) {
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
BlockPos.MutableBlockPos mutableBlockPos2 = new BlockPos.MutableBlockPos();
ChunkPos chunkPos = chunk.getPos();
LevelAccessor levelAccessor = chunk.getLevel();
for (int i = 0; i < this.index.length; i++) {
LevelChunkSection levelChunkSection = chunk.getSection(i);
int[] is = this.index[i];
this.index[i] = null;
if (is != null && is.length > 0) {
Direction[] directions = Direction.values();
PalettedContainer<BlockState> palettedContainer = levelChunkSection.getStates();
int j = chunk.getSectionYFromSectionIndex(i);
int k = SectionPos.sectionToBlockCoord(j);
for (int l : is) {
int m = l & 15;
int n = l >> 8 & 15;
int o = l >> 4 & 15;
mutableBlockPos.set(chunkPos.getMinBlockX() + m, k + n, chunkPos.getMinBlockZ() + o);
BlockState blockState = palettedContainer.get(l);
BlockState blockState2 = blockState;
for (Direction direction : directions) {
mutableBlockPos2.setWithOffset(mutableBlockPos, direction);
if (SectionPos.blockToSectionCoord(mutableBlockPos.getX()) == chunkPos.x && SectionPos.blockToSectionCoord(mutableBlockPos.getZ()) == chunkPos.z) {
blockState2 = updateState(blockState2, direction, levelAccessor, mutableBlockPos, mutableBlockPos2);
}
}
Block.updateOrDestroy(blockState, blockState2, levelAccessor, mutableBlockPos, 18);
}
}
}
for (int ix = 0; ix < this.index.length; ix++) {
if (this.index[ix] != null) {
LOGGER.warn("Discarding update data for section {} for chunk ({} {})", levelAccessor.getSectionYFromSectionIndex(ix), chunkPos.x, chunkPos.z);
}
this.index[ix] = null;
}
}
public boolean isEmpty() {
for (int[] is : this.index) {
if (is != null) {
return false;
}
}
return this.sides.isEmpty();
}
public CompoundTag write() {
CompoundTag compoundTag = new CompoundTag();
CompoundTag compoundTag2 = new CompoundTag();
for (int i = 0; i < this.index.length; i++) {
String string = String.valueOf(i);
if (this.index[i] != null && this.index[i].length != 0) {
compoundTag2.putIntArray(string, this.index[i]);
}
}
if (!compoundTag2.isEmpty()) {
compoundTag.put("Indices", compoundTag2);
}
int ix = 0;
for (Direction8 direction8 : this.sides) {
ix |= 1 << direction8.ordinal();
}
compoundTag.putByte("Sides", (byte)ix);
if (!this.neighborBlockTicks.isEmpty()) {
compoundTag.store("neighbor_block_ticks", BLOCK_TICKS_CODEC, this.neighborBlockTicks);
}
if (!this.neighborFluidTicks.isEmpty()) {
compoundTag.store("neighbor_fluid_ticks", FLUID_TICKS_CODEC, this.neighborFluidTicks);
}
return compoundTag;
}
public UpgradeData copy() {
return this == EMPTY ? EMPTY : new UpgradeData(this);
}
public interface BlockFixer {
BlockState updateShape(BlockState state, Direction direction, BlockState offsetState, LevelAccessor level, BlockPos pos, BlockPos offsetPos);
default void processChunk(LevelAccessor level) {
}
}
static enum BlockFixers implements UpgradeData.BlockFixer {
BLACKLIST(
"BLACKLIST",
0,
new Block[]{
Blocks.OBSERVER,
Blocks.NETHER_PORTAL,
Blocks.WHITE_CONCRETE_POWDER,
Blocks.ORANGE_CONCRETE_POWDER,
Blocks.MAGENTA_CONCRETE_POWDER,
Blocks.LIGHT_BLUE_CONCRETE_POWDER,
Blocks.YELLOW_CONCRETE_POWDER,
Blocks.LIME_CONCRETE_POWDER,
Blocks.PINK_CONCRETE_POWDER,
Blocks.GRAY_CONCRETE_POWDER,
Blocks.LIGHT_GRAY_CONCRETE_POWDER,
Blocks.CYAN_CONCRETE_POWDER,
Blocks.PURPLE_CONCRETE_POWDER,
Blocks.BLUE_CONCRETE_POWDER,
Blocks.BROWN_CONCRETE_POWDER,
Blocks.GREEN_CONCRETE_POWDER,
Blocks.RED_CONCRETE_POWDER,
Blocks.BLACK_CONCRETE_POWDER,
Blocks.ANVIL,
Blocks.CHIPPED_ANVIL,
Blocks.DAMAGED_ANVIL,
Blocks.DRAGON_EGG,
Blocks.GRAVEL,
Blocks.SAND,
Blocks.RED_SAND,
Blocks.OAK_SIGN,
Blocks.SPRUCE_SIGN,
Blocks.BIRCH_SIGN,
Blocks.ACACIA_SIGN,
Blocks.CHERRY_SIGN,
Blocks.JUNGLE_SIGN,
Blocks.DARK_OAK_SIGN,
Blocks.PALE_OAK_SIGN,
Blocks.OAK_WALL_SIGN,
Blocks.SPRUCE_WALL_SIGN,
Blocks.BIRCH_WALL_SIGN,
Blocks.ACACIA_WALL_SIGN,
Blocks.JUNGLE_WALL_SIGN,
Blocks.DARK_OAK_WALL_SIGN,
Blocks.PALE_OAK_WALL_SIGN,
Blocks.OAK_HANGING_SIGN,
Blocks.SPRUCE_HANGING_SIGN,
Blocks.BIRCH_HANGING_SIGN,
Blocks.ACACIA_HANGING_SIGN,
Blocks.JUNGLE_HANGING_SIGN,
Blocks.DARK_OAK_HANGING_SIGN,
Blocks.PALE_OAK_HANGING_SIGN,
Blocks.OAK_WALL_HANGING_SIGN,
Blocks.SPRUCE_WALL_HANGING_SIGN,
Blocks.BIRCH_WALL_HANGING_SIGN,
Blocks.ACACIA_WALL_HANGING_SIGN,
Blocks.JUNGLE_WALL_HANGING_SIGN,
Blocks.DARK_OAK_WALL_HANGING_SIGN,
Blocks.PALE_OAK_WALL_HANGING_SIGN
}
),
DEFAULT("DEFAULT", 1, new Block[0]),
CHEST("CHEST", 2, new Block[]{Blocks.CHEST, Blocks.TRAPPED_CHEST}),
LEAVES(
"LEAVES",
3,
true,
new Block[]{
Blocks.ACACIA_LEAVES,
Blocks.CHERRY_LEAVES,
Blocks.BIRCH_LEAVES,
Blocks.PALE_OAK_LEAVES,
Blocks.DARK_OAK_LEAVES,
Blocks.JUNGLE_LEAVES,
Blocks.OAK_LEAVES,
Blocks.SPRUCE_LEAVES
}
),
STEM_BLOCK("STEM_BLOCK", 4, new Block[]{Blocks.MELON_STEM, Blocks.PUMPKIN_STEM});
public static final Direction[] DIRECTIONS = Direction.values();
BlockFixers(final Block... blocks) {
this(false, blocks);
}
BlockFixers(final boolean chunkyFixer, final Block... blocks) {
for (Block block : blocks) {
UpgradeData.MAP.put(block, this);
}
if (chunkyFixer) {
UpgradeData.CHUNKY_FIXERS.add(this);
}
}
}
}