ChunkProtoTickListFix.java

net.minecraft.util.datafix.fixes.ChunkProtoTickListFix

信息

  • 全限定名:net.minecraft.util.datafix.fixes.ChunkProtoTickListFix
  • 类型:public class
  • 包:net.minecraft.util.datafix.fixes
  • 源码路径:src/main/java/net/minecraft/util/datafix/fixes/ChunkProtoTickListFix.java
  • 起始行号:L28
  • 继承:DataFix
  • 职责:

    TODO

字段/常量

  • SECTION_WIDTH

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L29
    • 说明:

      TODO

  • ALWAYS_WATERLOGGED

    • 类型: ImmutableSet<String>
    • 修饰符: private static final
    • 源码定位: L30
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.util.datafix.fixes.ChunkProtoTickListFix.PoorMansPalettedContainer
    • 类型: class
    • 修饰符: public static final
    • 源码定位: L196
    • 说明:

      TODO

构造器

public ChunkProtoTickListFix(Schema outputSchema) @ L34

  • 构造器名:ChunkProtoTickListFix
  • 源码定位:L34
  • 修饰符:public

参数:

  • outputSchema: Schema

说明:

TODO

方法

下面的方法块按源码顺序生成。

protected TypeRewriteRule makeRule() @ L38

  • 方法名:makeRule
  • 源码定位:L38
  • 返回类型:TypeRewriteRule
  • 修饰符:protected

参数:

说明:

TODO

private Dynamic<?> makeTickList(Dynamic<?> tag, Int2ObjectMap<Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer>> palettedContainers, byte sectionMinY, int sectionX, int sectionZ, String protoTickListTag, Function<Dynamic<?>,String> typeGetter) @ L124

  • 方法名:makeTickList
  • 源码定位:L124
  • 返回类型:Dynamic<?>
  • 修饰符:private

参数:

  • tag: Dynamic<?>
  • palettedContainers: Int2ObjectMap<Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer>>
  • sectionMinY: byte
  • sectionX: int
  • sectionZ: int
  • protoTickListTag: String
  • typeGetter: Function<Dynamic<?>,String>

说明:

TODO

private static String getBlock(Dynamic<?> blockState) @ L150

  • 方法名:getBlock
  • 源码定位:L150
  • 返回类型:String
  • 修饰符:private static

参数:

  • blockState: Dynamic<?>

说明:

TODO

private static String getLiquid(Dynamic<?> blockState) @ L154

  • 方法名:getLiquid
  • 源码定位:L154
  • 返回类型:String
  • 修饰符:private static

参数:

  • blockState: Dynamic<?>

说明:

TODO

private Dynamic<?> createTick(Dynamic<?> tag, Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer> container, int sectionX, int sectionY, int sectionZ, int pos, Function<Dynamic<?>,String> typeGetter) @ L171

  • 方法名:createTick
  • 源码定位:L171
  • 返回类型:Dynamic<?>
  • 修饰符:private

参数:

  • tag: Dynamic<?>
  • container: Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer>
  • sectionX: int
  • sectionY: int
  • sectionZ: int
  • pos: int
  • typeGetter: Function<Dynamic<?>,String>

说明:

TODO

代码

public class ChunkProtoTickListFix extends DataFix {
    private static final int SECTION_WIDTH = 16;
    private static final ImmutableSet<String> ALWAYS_WATERLOGGED = ImmutableSet.of(
        "minecraft:bubble_column", "minecraft:kelp", "minecraft:kelp_plant", "minecraft:seagrass", "minecraft:tall_seagrass"
    );
 
    public ChunkProtoTickListFix(Schema outputSchema) {
        super(outputSchema, false);
    }
 
    @Override
    protected TypeRewriteRule makeRule() {
        Type<?> chunkType = this.getInputSchema().getType(References.CHUNK);
        OpticFinder<?> levelFinder = chunkType.findField("Level");
        OpticFinder<?> sectionsFinder = levelFinder.type().findField("Sections");
        OpticFinder<?> sectionFinder = ((ListType)sectionsFinder.type()).getElement().finder();
        OpticFinder<?> blockStateContainerFinder = sectionFinder.type().findField("block_states");
        OpticFinder<?> biomeContainerFinder = sectionFinder.type().findField("biomes");
        OpticFinder<?> blockStatePaletteFinder = blockStateContainerFinder.type().findField("palette");
        OpticFinder<?> tileTickFinder = levelFinder.type().findField("TileTicks");
        return this.fixTypeEverywhereTyped(
            "ChunkProtoTickListFix",
            chunkType,
            chunk -> chunk.updateTyped(
                levelFinder,
                level -> {
                    level = level.update(
                        DSL.remainderFinder(),
                        tag -> DataFixUtils.orElse(tag.get("LiquidTicks").result().map(v -> tag.set("fluid_ticks", (Dynamic<?>)v).remove("LiquidTicks")), tag)
                    );
                    Dynamic<?> chunkTag = level.get(DSL.remainderFinder());
                    MutableInt lowestY = new MutableInt();
                    Int2ObjectMap<Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer>> palettedContainers = new Int2ObjectArrayMap<>();
                    level.getOptionalTyped(sectionsFinder)
                        .ifPresent(
                            sections -> sections.getAllTyped(sectionFinder)
                                .forEach(
                                    section -> {
                                        Dynamic<?> sectionRemainder = section.get(DSL.remainderFinder());
                                        int sectionY = sectionRemainder.get("Y").asInt(Integer.MAX_VALUE);
                                        if (sectionY != Integer.MAX_VALUE) {
                                            if (section.getOptionalTyped(biomeContainerFinder).isPresent()) {
                                                lowestY.setValue(Math.min(sectionY, lowestY.intValue()));
                                            }
 
                                            section.getOptionalTyped(blockStateContainerFinder)
                                                .ifPresent(
                                                    blockContainer -> palettedContainers.put(
                                                        sectionY,
                                                        Suppliers.memoize(
                                                            () -> {
                                                                List<? extends Dynamic<?>> palette = blockContainer.getOptionalTyped(blockStatePaletteFinder)
                                                                    .map(
                                                                        x -> x.write()
                                                                            .result()
                                                                            .map(r -> r.asList(Function.identity()))
                                                                            .orElse(Collections.emptyList())
                                                                    )
                                                                    .orElse(Collections.emptyList());
                                                                long[] data = blockContainer.get(DSL.remainderFinder()).get("data").asLongStream().toArray();
                                                                return new ChunkProtoTickListFix.PoorMansPalettedContainer(palette, data);
                                                            }
                                                        )
                                                    )
                                                );
                                        }
                                    }
                                )
                        );
                    byte sectionMinY = lowestY.byteValue();
                    level = level.update(DSL.remainderFinder(), remainder -> remainder.update("yPos", y -> y.createByte(sectionMinY)));
                    if (!level.getOptionalTyped(tileTickFinder).isPresent() && !chunkTag.get("fluid_ticks").result().isPresent()) {
                        int sectionX = chunkTag.get("xPos").asInt(0);
                        int sectionZ = chunkTag.get("zPos").asInt(0);
                        Dynamic<?> fluidTicks = this.makeTickList(
                            chunkTag, palettedContainers, sectionMinY, sectionX, sectionZ, "LiquidsToBeTicked", ChunkProtoTickListFix::getLiquid
                        );
                        Dynamic<?> blockTicks = this.makeTickList(
                            chunkTag, palettedContainers, sectionMinY, sectionX, sectionZ, "ToBeTicked", ChunkProtoTickListFix::getBlock
                        );
                        Optional<? extends Pair<? extends Typed<?>, ?>> parsedBlockTicks = tileTickFinder.type().readTyped(blockTicks).result();
                        if (parsedBlockTicks.isPresent()) {
                            level = level.set(tileTickFinder, (Typed<?>)parsedBlockTicks.get().getFirst());
                        }
 
                        return level.update(
                            DSL.remainderFinder(), remainder -> remainder.remove("ToBeTicked").remove("LiquidsToBeTicked").set("fluid_ticks", fluidTicks)
                        );
                    } else {
                        return level;
                    }
                }
            )
        );
    }
 
    private Dynamic<?> makeTickList(
        Dynamic<?> tag,
        Int2ObjectMap<Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer>> palettedContainers,
        byte sectionMinY,
        int sectionX,
        int sectionZ,
        String protoTickListTag,
        Function<Dynamic<?>, String> typeGetter
    ) {
        Stream<Dynamic<?>> newTickList = Stream.empty();
        List<? extends Dynamic<?>> ticksPerSection = tag.get(protoTickListTag).asList(Function.identity());
 
        for (int sectionYIndex = 0; sectionYIndex < ticksPerSection.size(); sectionYIndex++) {
            int sectionY = sectionYIndex + sectionMinY;
            Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer> container = palettedContainers.get(sectionY);
            Stream<? extends Dynamic<?>> newTickListForSection = ticksPerSection.get(sectionYIndex)
                .asStream()
                .mapToInt(pos -> pos.asShort((short)-1))
                .filter(pos -> pos > 0)
                .mapToObj(pos -> this.createTick(tag, container, sectionX, sectionY, sectionZ, pos, typeGetter));
            newTickList = Stream.concat(newTickList, newTickListForSection);
        }
 
        return tag.createList(newTickList);
    }
 
    private static String getBlock(@Nullable Dynamic<?> blockState) {
        return blockState != null ? blockState.get("Name").asString("minecraft:air") : "minecraft:air";
    }
 
    private static String getLiquid(@Nullable Dynamic<?> blockState) {
        if (blockState == null) {
            return "minecraft:empty";
        } else {
            String block = blockState.get("Name").asString("");
            if ("minecraft:water".equals(block)) {
                return blockState.get("Properties").get("level").asInt(0) == 0 ? "minecraft:water" : "minecraft:flowing_water";
            } else if ("minecraft:lava".equals(block)) {
                return blockState.get("Properties").get("level").asInt(0) == 0 ? "minecraft:lava" : "minecraft:flowing_lava";
            } else {
                return !ALWAYS_WATERLOGGED.contains(block) && !blockState.get("Properties").get("waterlogged").asBoolean(false)
                    ? "minecraft:empty"
                    : "minecraft:water";
            }
        }
    }
 
    private Dynamic<?> createTick(
        Dynamic<?> tag,
        @Nullable Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer> container,
        int sectionX,
        int sectionY,
        int sectionZ,
        int pos,
        Function<Dynamic<?>, String> typeGetter
    ) {
        int relativeX = pos & 15;
        int relativeY = pos >>> 4 & 15;
        int relativeZ = pos >>> 8 & 15;
        String type = typeGetter.apply(container != null ? container.get().get(relativeX, relativeY, relativeZ) : null);
        return tag.createMap(
            ImmutableMap.<Dynamic<?>, Dynamic<?>>builder()
                .put(tag.createString("i"), tag.createString(type))
                .put(tag.createString("x"), tag.createInt(sectionX * 16 + relativeX))
                .put(tag.createString("y"), tag.createInt(sectionY * 16 + relativeY))
                .put(tag.createString("z"), tag.createInt(sectionZ * 16 + relativeZ))
                .put(tag.createString("t"), tag.createInt(0))
                .put(tag.createString("p"), tag.createInt(0))
                .build()
        );
    }
 
    public static final class PoorMansPalettedContainer {
        private static final long SIZE_BITS = 4L;
        private final List<? extends Dynamic<?>> palette;
        private final long[] data;
        private final int bits;
        private final long mask;
        private final int valuesPerLong;
 
        public PoorMansPalettedContainer(List<? extends Dynamic<?>> palette, long[] data) {
            this.palette = palette;
            this.data = data;
            this.bits = Math.max(4, ChunkHeightAndBiomeFix.ceillog2(palette.size()));
            this.mask = (1L << this.bits) - 1L;
            this.valuesPerLong = (char)(64 / this.bits);
        }
 
        public @Nullable Dynamic<?> get(int x, int y, int z) {
            int entryCount = this.palette.size();
            if (entryCount < 1) {
                return null;
            } else if (entryCount == 1) {
                return (Dynamic<?>)this.palette.getFirst();
            } else {
                int index = this.getIndex(x, y, z);
                int cellIndex = index / this.valuesPerLong;
                if (cellIndex >= 0 && cellIndex < this.data.length) {
                    long cellValue = this.data[cellIndex];
                    int bitIndex = (index - cellIndex * this.valuesPerLong) * this.bits;
                    int paletteIndex = (int)(cellValue >> bitIndex & this.mask);
                    return (Dynamic<?>)(paletteIndex >= 0 && paletteIndex < entryCount ? this.palette.get(paletteIndex) : null);
                } else {
                    return null;
                }
            }
        }
 
        private int getIndex(int x, int y, int z) {
            return (y << 4 | z) << 4 | x;
        }
 
        public List<? extends Dynamic<?>> palette() {
            return this.palette;
        }
 
        public long[] data() {
            return this.data;
        }
    }
}

引用的其他类