package net.minecraft.world.level.chunk; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder.Instance; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArraySet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.Int2IntMap.Entry; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.function.Consumer; import java.util.function.IntUnaryOperator; import java.util.function.Predicate; import java.util.stream.LongStream; import javax.annotation.Nullable; import net.minecraft.core.IdMap; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.VarInt; import net.minecraft.util.BitStorage; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.Mth; import net.minecraft.util.SimpleBitStorage; import net.minecraft.util.ThreadingDetector; import net.minecraft.util.ZeroBitStorage; public class PalettedContainer implements PaletteResize, PalettedContainerRO { private static final int MIN_PALETTE_BITS = 0; private final PaletteResize dummyPaletteResize = (p_238275_, p_238276_) -> 0; private final IdMap registry; private volatile PalettedContainer.Data data; private final PalettedContainer.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(IdMap p_238372_, Codec p_238373_, PalettedContainer.Strategy p_238374_, T p_238375_) { PalettedContainerRO.Unpacker> unpacker = PalettedContainer::unpack; return codec(p_238372_, p_238373_, p_238374_, p_238375_, unpacker); } public static Codec> codecRO(IdMap p_238419_, Codec p_238420_, PalettedContainer.Strategy p_238421_, T p_238422_) { PalettedContainerRO.Unpacker> unpacker = (p_327412_, p_327413_, p_327414_) -> unpack(p_327412_, p_327413_, p_327414_) .map(p_238264_ -> (PalettedContainerRO)p_238264_); return codec(p_238419_, p_238420_, p_238421_, p_238422_, unpacker); } private static > Codec codec( IdMap p_238428_, Codec p_238429_, PalettedContainer.Strategy p_238430_, T p_238431_, PalettedContainerRO.Unpacker p_238432_ ) { return RecordCodecBuilder.create( p_327417_ -> p_327417_.group( p_238429_.mapResult(ExtraCodecs.orElsePartial(p_238431_)).listOf().fieldOf("palette").forGetter(PalettedContainerRO.PackedData::paletteEntries), Codec.LONG_STREAM.lenientOptionalFieldOf("data").forGetter(PalettedContainerRO.PackedData::storage) ) .apply(p_327417_, PalettedContainerRO.PackedData::new) ) .comapFlatMap( p_238262_ -> p_238432_.read(p_238428_, p_238430_, (PalettedContainerRO.PackedData)p_238262_), p_238263_ -> p_238263_.pack(p_238428_, p_238430_) ); } public PalettedContainer( IdMap p_188035_, PalettedContainer.Strategy p_188036_, PalettedContainer.Configuration p_188037_, BitStorage p_188038_, List p_188039_ ) { this.registry = p_188035_; this.strategy = p_188036_; this.data = new PalettedContainer.Data<>(p_188037_, p_188038_, p_188037_.factory().create(p_188037_.bits(), p_188035_, this, p_188039_)); } private PalettedContainer(IdMap p_199928_, PalettedContainer.Strategy p_199929_, PalettedContainer.Data p_199930_) { this.registry = p_199928_; this.strategy = p_199929_; this.data = p_199930_; } private PalettedContainer(PalettedContainer p_368978_) { this.registry = p_368978_.registry; this.strategy = p_368978_.strategy; this.data = p_368978_.data.copy(this); } public PalettedContainer(IdMap p_188041_, T p_188042_, PalettedContainer.Strategy p_188043_) { this.strategy = p_188043_; this.registry = p_188041_; this.data = this.createOrReuseData(null, 0); this.data.palette.idFor(p_188042_); } private PalettedContainer.Data createOrReuseData(@Nullable PalettedContainer.Data p_188052_, int p_188053_) { PalettedContainer.Configuration configuration = this.strategy.getConfiguration(this.registry, p_188053_); return p_188052_ != null && configuration.equals(p_188052_.configuration()) ? p_188052_ : configuration.createData(this.registry, this, this.strategy.size()); } @Override public int onResize(int p_63142_, T p_63143_) { PalettedContainer.Data data = this.data; PalettedContainer.Data data1 = this.createOrReuseData(data, p_63142_); data1.copyFrom(data.palette, data.storage); this.data = data1; return data1.palette.idFor(p_63143_); } public T getAndSet(int p_63092_, int p_63093_, int p_63094_, T p_63095_) { this.acquire(); Object object; try { object = this.getAndSet(this.strategy.getIndex(p_63092_, p_63093_, p_63094_), p_63095_); } finally { this.release(); } return (T)object; } public T getAndSetUnchecked(int p_63128_, int p_63129_, int p_63130_, T p_63131_) { return this.getAndSet(this.strategy.getIndex(p_63128_, p_63129_, p_63130_), p_63131_); } private T getAndSet(int p_63097_, T p_63098_) { int i = this.data.palette.idFor(p_63098_); int j = this.data.storage.getAndSet(p_63097_, i); return this.data.palette.valueFor(j); } public void set(int p_156471_, int p_156472_, int p_156473_, T p_156474_) { this.acquire(); try { this.set(this.strategy.getIndex(p_156471_, p_156472_, p_156473_), p_156474_); } finally { this.release(); } } private void set(int p_63133_, T p_63134_) { int i = this.data.palette.idFor(p_63134_); this.data.storage.set(p_63133_, i); } @Override public T get(int p_63088_, int p_63089_, int p_63090_) { return this.get(this.strategy.getIndex(p_63088_, p_63089_, p_63090_)); } protected T get(int p_63086_) { PalettedContainer.Data data = this.data; return data.palette.valueFor(data.storage.get(p_63086_)); } @Override public void getAll(Consumer p_196880_) { Palette palette = this.data.palette(); IntSet intset = new IntArraySet(); this.data.storage.getAll(intset::add); intset.forEach(p_238274_ -> p_196880_.accept(palette.valueFor(p_238274_))); } public void read(FriendlyByteBuf p_63119_) { this.acquire(); try { int i = p_63119_.readByte(); PalettedContainer.Data data = this.createOrReuseData(this.data, i); data.palette.read(p_63119_); p_63119_.readFixedSizeLongArray(data.storage.getRaw()); this.data = data; } finally { this.release(); } } @Override public void write(FriendlyByteBuf p_63136_) { this.acquire(); try { this.data.write(p_63136_); } finally { this.release(); } } private static DataResult> unpack( IdMap p_188068_, PalettedContainer.Strategy p_188069_, PalettedContainerRO.PackedData p_238258_ ) { List list = p_238258_.paletteEntries(); int i = p_188069_.size(); int j = p_188069_.calculateBitsForSerialization(p_188068_, list.size()); PalettedContainer.Configuration configuration = p_188069_.getConfiguration(p_188068_, j); BitStorage bitstorage; if (j == 0) { bitstorage = new ZeroBitStorage(i); } else { Optional optional = p_238258_.storage(); if (optional.isEmpty()) { return DataResult.error(() -> "Missing values for non-zero storage"); } long[] along = optional.get().toArray(); try { if (configuration.factory() == PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY) { Palette palette = new HashMapPalette<>(p_188068_, j, (p_238278_, p_238279_) -> 0, list); SimpleBitStorage simplebitstorage = new SimpleBitStorage(j, i, along); int[] aint = new int[i]; simplebitstorage.unpack(aint); swapPalette(aint, p_238283_ -> p_188068_.getId(palette.valueFor(p_238283_))); bitstorage = new SimpleBitStorage(configuration.bits(), i, aint); } else { bitstorage = new SimpleBitStorage(configuration.bits(), i, along); } } catch (SimpleBitStorage.InitializationException simplebitstorage$initializationexception) { return DataResult.error(() -> "Failed to read PalettedContainer: " + simplebitstorage$initializationexception.getMessage()); } } return DataResult.success(new PalettedContainer<>(p_188068_, p_188069_, configuration, bitstorage, list)); } @Override public PalettedContainerRO.PackedData pack(IdMap p_188065_, PalettedContainer.Strategy p_188066_) { this.acquire(); PalettedContainerRO.PackedData palettedcontainerro$packeddata; try { HashMapPalette hashmappalette = new HashMapPalette<>(p_188065_, this.data.storage.getBits(), this.dummyPaletteResize); int i = p_188066_.size(); int[] aint = new int[i]; this.data.storage.unpack(aint); swapPalette(aint, p_198178_ -> hashmappalette.idFor(this.data.palette.valueFor(p_198178_))); int j = p_188066_.calculateBitsForSerialization(p_188065_, hashmappalette.getSize()); Optional optional; if (j != 0) { SimpleBitStorage simplebitstorage = new SimpleBitStorage(j, i, aint); optional = Optional.of(Arrays.stream(simplebitstorage.getRaw())); } else { optional = Optional.empty(); } palettedcontainerro$packeddata = new PalettedContainerRO.PackedData<>(hashmappalette.getEntries(), optional); } finally { this.release(); } return palettedcontainerro$packeddata; } private static void swapPalette(int[] p_198190_, IntUnaryOperator p_198191_) { int i = -1; int j = -1; for (int k = 0; k < p_198190_.length; k++) { int l = p_198190_[k]; if (l != i) { i = l; j = p_198191_.applyAsInt(l); } p_198190_[k] = j; } } @Override public int getSerializedSize() { return this.data.getSerializedSize(); } @Override public boolean maybeHas(Predicate p_63110_) { return this.data.palette.maybeHas(p_63110_); } @Override public PalettedContainer copy() { return new PalettedContainer<>(this); } @Override public PalettedContainer recreate() { return new PalettedContainer<>(this.registry, this.data.palette.valueFor(0), this.strategy); } @Override public void count(PalettedContainer.CountConsumer p_63100_) { if (this.data.palette.getSize() == 1) { p_63100_.accept(this.data.palette.valueFor(0), this.data.storage.getSize()); } else { Int2IntOpenHashMap int2intopenhashmap = new Int2IntOpenHashMap(); this.data.storage.getAll(p_238269_ -> int2intopenhashmap.addTo(p_238269_, 1)); int2intopenhashmap.int2IntEntrySet() .forEach(p_238271_ -> p_63100_.accept(this.data.palette.valueFor(p_238271_.getIntKey()), p_238271_.getIntValue())); } } record Configuration(Palette.Factory factory, int bits) { public PalettedContainer.Data createData(IdMap p_188092_, PaletteResize p_188093_, int p_188094_) { BitStorage bitstorage = (BitStorage)(this.bits == 0 ? new ZeroBitStorage(p_188094_) : new SimpleBitStorage(this.bits, p_188094_)); Palette palette = this.factory.create(this.bits, p_188092_, p_188093_, List.of()); return new PalettedContainer.Data<>(this, bitstorage, palette); } } @FunctionalInterface public interface CountConsumer { void accept(T p_63145_, int p_63146_); } record Data(PalettedContainer.Configuration configuration, BitStorage storage, Palette palette) { public void copyFrom(Palette p_188112_, BitStorage p_188113_) { for (int i = 0; i < p_188113_.getSize(); i++) { T t = p_188112_.valueFor(p_188113_.get(i)); this.storage.set(i, this.palette.idFor(t)); } } public int getSerializedSize() { return 1 + this.palette.getSerializedSize() + VarInt.getByteSize(this.storage.getRaw().length) + this.storage.getRaw().length * 8; } public void write(FriendlyByteBuf p_188115_) { p_188115_.writeByte(this.storage.getBits()); this.palette.write(p_188115_); p_188115_.writeFixedSizeLongArray(this.storage.getRaw()); } public PalettedContainer.Data copy(PaletteResize p_361657_) { return new PalettedContainer.Data<>(this.configuration, this.storage.copy(), this.palette.copy(p_361657_)); } } public abstract static class Strategy { public static final Palette.Factory SINGLE_VALUE_PALETTE_FACTORY = SingleValuePalette::create; public static final Palette.Factory LINEAR_PALETTE_FACTORY = LinearPalette::create; public static final Palette.Factory HASHMAP_PALETTE_FACTORY = HashMapPalette::create; static final Palette.Factory GLOBAL_PALETTE_FACTORY = GlobalPalette::create; public static final PalettedContainer.Strategy SECTION_STATES = new PalettedContainer.Strategy(4) { @Override public PalettedContainer.Configuration getConfiguration(IdMap p_188157_, int p_188158_) { return switch (p_188158_) { case 0 -> new PalettedContainer.Configuration(SINGLE_VALUE_PALETTE_FACTORY, p_188158_); case 1, 2, 3, 4 -> new PalettedContainer.Configuration(LINEAR_PALETTE_FACTORY, 4); case 5, 6, 7, 8 -> new PalettedContainer.Configuration(HASHMAP_PALETTE_FACTORY, p_188158_); default -> new PalettedContainer.Configuration(PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY, Mth.ceillog2(p_188157_.size())); }; } }; public static final PalettedContainer.Strategy SECTION_BIOMES = new PalettedContainer.Strategy(2) { @Override public PalettedContainer.Configuration getConfiguration(IdMap p_188162_, int p_188163_) { return switch (p_188163_) { case 0 -> new PalettedContainer.Configuration(SINGLE_VALUE_PALETTE_FACTORY, p_188163_); case 1, 2, 3 -> new PalettedContainer.Configuration(LINEAR_PALETTE_FACTORY, p_188163_); default -> new PalettedContainer.Configuration(PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY, Mth.ceillog2(p_188162_.size())); }; } }; private final int sizeBits; Strategy(int p_188143_) { this.sizeBits = p_188143_; } public int size() { return 1 << this.sizeBits * 3; } public int getIndex(int p_188146_, int p_188147_, int p_188148_) { return (p_188147_ << this.sizeBits | p_188148_) << this.sizeBits | p_188146_; } public abstract PalettedContainer.Configuration getConfiguration(IdMap p_188149_, int p_188150_); int calculateBitsForSerialization(IdMap p_188152_, int p_188153_) { int i = Mth.ceillog2(p_188153_); PalettedContainer.Configuration configuration = this.getConfiguration(p_188152_, i); return configuration.factory() == GLOBAL_PALETTE_FACTORY ? i : configuration.bits(); } } }