/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.annotations.VisibleForTesting * com.mojang.datafixers.kinds.App * com.mojang.datafixers.kinds.Applicative * com.mojang.serialization.Codec * com.mojang.serialization.DataResult * com.mojang.serialization.codecs.RecordCodecBuilder * it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap * it.unimi.dsi.fastutil.ints.IntArraySet * it.unimi.dsi.fastutil.ints.IntSet * org.jspecify.annotations.Nullable */ package net.minecraft.world.level.chunk; import com.google.common.annotations.VisibleForTesting; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.Applicative; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArraySet; import it.unimi.dsi.fastutil.ints.IntSet; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.LongStream; import net.minecraft.core.IdMap; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.util.BitStorage; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.SimpleBitStorage; import net.minecraft.util.ThreadingDetector; import net.minecraft.util.ZeroBitStorage; import net.minecraft.world.level.chunk.Configuration; import net.minecraft.world.level.chunk.HashMapPalette; import net.minecraft.world.level.chunk.Palette; import net.minecraft.world.level.chunk.PaletteResize; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.Strategy; import org.jspecify.annotations.Nullable; public class PalettedContainer implements PaletteResize, PalettedContainerRO { private static final int MIN_PALETTE_BITS = 0; private volatile Data data; private final Strategy strategy; private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); public void acquire() { this.threadingDetector.checkAndLock(); } public void release() { this.threadingDetector.checkAndUnlock(); } public static Codec> codecRW(Codec elementCodec, Strategy strategy, T defaultValue) { PalettedContainerRO.Unpacker unpacker = PalettedContainer::unpack; return PalettedContainer.codec(elementCodec, strategy, defaultValue, unpacker); } public static Codec> codecRO(Codec elementCodec, Strategy strategy, T defaultValue) { PalettedContainerRO.Unpacker unpacker = (s, data) -> PalettedContainer.unpack(s, data).map(e -> e); return PalettedContainer.codec(elementCodec, strategy, defaultValue, unpacker); } private static > Codec codec(Codec elementCodec, Strategy strategy, T defaultValue, PalettedContainerRO.Unpacker unpacker) { return RecordCodecBuilder.create(i -> i.group((App)elementCodec.mapResult(ExtraCodecs.orElsePartial(defaultValue)).listOf().fieldOf("palette").forGetter(PalettedContainerRO.PackedData::paletteEntries), (App)Codec.LONG_STREAM.lenientOptionalFieldOf("data").forGetter(PalettedContainerRO.PackedData::storage)).apply((Applicative)i, PalettedContainerRO.PackedData::new)).comapFlatMap(discData -> unpacker.read(strategy, (PalettedContainerRO.PackedData)discData), palettedContainer -> palettedContainer.pack(strategy)); } private PalettedContainer(Strategy strategy, Configuration dataConfiguration, BitStorage storage, Palette palette) { this.strategy = strategy; this.data = new Data(dataConfiguration, storage, palette); } private PalettedContainer(PalettedContainer source) { this.strategy = source.strategy; this.data = source.data.copy(); } public PalettedContainer(T initialValue, Strategy strategy) { this.strategy = strategy; this.data = this.createOrReuseData(null, 0); this.data.palette.idFor(initialValue, this); } private Data createOrReuseData(@Nullable Data oldData, int targetBits) { Configuration dataConfiguration = this.strategy.getConfigurationForBitCount(targetBits); if (oldData != null && dataConfiguration.equals(oldData.configuration())) { return oldData; } BitStorage storage = dataConfiguration.bitsInMemory() == 0 ? new ZeroBitStorage(this.strategy.entryCount()) : new SimpleBitStorage(dataConfiguration.bitsInMemory(), this.strategy.entryCount()); Palette palette = dataConfiguration.createPalette(this.strategy, List.of()); return new Data(dataConfiguration, storage, palette); } @Override public int onResize(int bits, T lastAddedValue) { Data oldData = this.data; Data newData = this.createOrReuseData(oldData, bits); newData.copyFrom(oldData.palette, oldData.storage); this.data = newData; return newData.palette.idFor(lastAddedValue, PaletteResize.noResizeExpected()); } /* * WARNING - Removed try catching itself - possible behaviour change. */ public T getAndSet(int x, int y, int z, T value) { this.acquire(); try { T t = this.getAndSet(this.strategy.getIndex(x, y, z), value); return t; } finally { this.release(); } } public T getAndSetUnchecked(int x, int y, int z, T value) { return this.getAndSet(this.strategy.getIndex(x, y, z), value); } private T getAndSet(int index, T value) { int id = this.data.palette.idFor(value, this); int oldId = this.data.storage.getAndSet(index, id); return this.data.palette.valueFor(oldId); } /* * WARNING - Removed try catching itself - possible behaviour change. */ public void set(int x, int y, int z, T value) { this.acquire(); try { this.set(this.strategy.getIndex(x, y, z), value); } finally { this.release(); } } private void set(int index, T value) { int id = this.data.palette.idFor(value, this); this.data.storage.set(index, id); } @Override public T get(int x, int y, int z) { return this.get(this.strategy.getIndex(x, y, z)); } protected T get(int index) { Data data = this.data; return data.palette.valueFor(data.storage.get(index)); } @Override public void getAll(Consumer consumer) { Palette palette = this.data.palette(); IntArraySet allExistingEntries = new IntArraySet(); this.data.storage.getAll(arg_0 -> ((IntSet)allExistingEntries).add(arg_0)); allExistingEntries.forEach(state -> consumer.accept(palette.valueFor(state))); } /* * WARNING - Removed try catching itself - possible behaviour change. */ public void read(FriendlyByteBuf buffer) { this.acquire(); try { byte newBits = buffer.readByte(); Data newData = this.createOrReuseData(this.data, newBits); newData.palette.read(buffer, this.strategy.globalMap()); buffer.readFixedSizeLongArray(newData.storage.getRaw()); this.data = newData; } finally { this.release(); } } @Override public void write(FriendlyByteBuf buffer) { this.acquire(); try { this.data.write(buffer, this.strategy.globalMap()); } finally { this.release(); } } @VisibleForTesting public static DataResult> unpack(Strategy strategy, PalettedContainerRO.PackedData discData) { BitStorage storage; Palette palette; List paletteEntries = discData.paletteEntries(); int entryCount = strategy.entryCount(); Configuration storedConfiguration = strategy.getConfigurationForPaletteSize(paletteEntries.size()); int bitsOnDisc = storedConfiguration.bitsInStorage(); if (discData.bitsPerEntry() != -1 && bitsOnDisc != discData.bitsPerEntry()) { return DataResult.error(() -> "Invalid bit count, calculated " + bitsOnDisc + ", but container declared " + discData.bitsPerEntry()); } if (storedConfiguration.bitsInMemory() == 0) { palette = storedConfiguration.createPalette(strategy, paletteEntries); storage = new ZeroBitStorage(entryCount); } else { Optional dataOpt = discData.storage(); if (dataOpt.isEmpty()) { return DataResult.error(() -> "Missing values for non-zero storage"); } long[] data = dataOpt.get().toArray(); try { if (storedConfiguration.alwaysRepack() || storedConfiguration.bitsInMemory() != bitsOnDisc) { HashMapPalette oldPalette = new HashMapPalette(bitsOnDisc, paletteEntries); SimpleBitStorage oldStorage = new SimpleBitStorage(bitsOnDisc, entryCount, data); Palette newPalette = storedConfiguration.createPalette(strategy, paletteEntries); int[] newContents = PalettedContainer.reencodeContents(oldStorage, oldPalette, newPalette); palette = newPalette; storage = new SimpleBitStorage(storedConfiguration.bitsInMemory(), entryCount, newContents); } else { palette = storedConfiguration.createPalette(strategy, paletteEntries); storage = new SimpleBitStorage(storedConfiguration.bitsInMemory(), entryCount, data); } } catch (SimpleBitStorage.InitializationException exception) { return DataResult.error(() -> "Failed to read PalettedContainer: " + exception.getMessage()); } } return DataResult.success(new PalettedContainer(strategy, storedConfiguration, storage, palette)); } /* * WARNING - Removed try catching itself - possible behaviour change. */ @Override public PalettedContainerRO.PackedData pack(Strategy strategy) { this.acquire(); try { Optional values; BitStorage currentStorage = this.data.storage; Palette currentPalette = this.data.palette; HashMapPalette newPalette = new HashMapPalette(currentStorage.getBits()); int entryCount = strategy.entryCount(); int[] newContents = PalettedContainer.reencodeContents(currentStorage, currentPalette, newPalette); Configuration storedConfiguration = strategy.getConfigurationForPaletteSize(newPalette.getSize()); int bitsOnDisc = storedConfiguration.bitsInStorage(); if (bitsOnDisc != 0) { SimpleBitStorage storage = new SimpleBitStorage(bitsOnDisc, entryCount, newContents); values = Optional.of(Arrays.stream(storage.getRaw())); } else { values = Optional.empty(); } PalettedContainerRO.PackedData packedData = new PalettedContainerRO.PackedData(newPalette.getEntries(), values, bitsOnDisc); return packedData; } finally { this.release(); } } private static int[] reencodeContents(BitStorage storage, Palette oldPalette, Palette newPalette) { int[] buffer = new int[storage.getSize()]; storage.unpack(buffer); PaletteResize dummyResizer = PaletteResize.noResizeExpected(); int lastReadId = -1; int lastWrittenId = -1; for (int index = 0; index < buffer.length; ++index) { int id = buffer[index]; if (id != lastReadId) { lastReadId = id; lastWrittenId = newPalette.idFor(oldPalette.valueFor(id), dummyResizer); } buffer[index] = lastWrittenId; } return buffer; } @Override public int getSerializedSize() { return this.data.getSerializedSize(this.strategy.globalMap()); } @Override public int bitsPerEntry() { return this.data.storage().getBits(); } @Override public boolean maybeHas(Predicate predicate) { return this.data.palette.maybeHas(predicate); } @Override public PalettedContainer copy() { return new PalettedContainer(this); } @Override public PalettedContainer recreate() { return new PalettedContainer(this.data.palette.valueFor(0), this.strategy); } @Override public void count(CountConsumer output) { if (this.data.palette.getSize() == 1) { output.accept(this.data.palette.valueFor(0), this.data.storage.getSize()); return; } Int2IntOpenHashMap counts = new Int2IntOpenHashMap(); this.data.storage.getAll((int state) -> counts.addTo(state, 1)); counts.int2IntEntrySet().forEach(entry -> output.accept(this.data.palette.valueFor(entry.getIntKey()), entry.getIntValue())); } private record Data(Configuration configuration, BitStorage storage, Palette palette) { public void copyFrom(Palette oldPalette, BitStorage oldStorage) { PaletteResize dummyResizer = PaletteResize.noResizeExpected(); for (int i = 0; i < oldStorage.getSize(); ++i) { T value = oldPalette.valueFor(oldStorage.get(i)); this.storage.set(i, this.palette.idFor(value, dummyResizer)); } } public int getSerializedSize(IdMap globalMap) { return 1 + this.palette.getSerializedSize(globalMap) + this.storage.getRaw().length * 8; } public void write(FriendlyByteBuf buffer, IdMap globalMap) { buffer.writeByte(this.storage.getBits()); this.palette.write(buffer, globalMap); buffer.writeFixedSizeLongArray(this.storage.getRaw()); } public Data copy() { return new Data(this.configuration, this.storage.copy(), this.palette.copy()); } } @FunctionalInterface public static interface CountConsumer { public void accept(T var1, int var2); } }