Code/net/minecraft/world/level/lighting/LayerLightSectionStorage.java

337 lines
12 KiB
Java
Raw Normal View History

2025-07-01 06:20:03 +00:00
package net.minecraft.world.level.lighting;
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.world.level.chunk.LightChunkGetter;
public abstract class LayerLightSectionStorage<M extends DataLayerStorageMap<M>> {
private final LightLayer layer;
protected final LightChunkGetter chunkSource;
protected final Long2ByteMap sectionStates = new Long2ByteOpenHashMap();
private final LongSet columnsWithSources = new LongOpenHashSet();
protected volatile M visibleSectionData;
protected final M updatingSectionData;
protected final LongSet changedSections = new LongOpenHashSet();
protected final LongSet sectionsAffectedByLightUpdates = new LongOpenHashSet();
protected final Long2ObjectMap<DataLayer> queuedSections = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
private final LongSet columnsToRetainQueuedDataFor = new LongOpenHashSet();
private final LongSet toRemove = new LongOpenHashSet();
protected volatile boolean hasInconsistencies;
protected LayerLightSectionStorage(LightLayer p_75745_, LightChunkGetter p_75746_, M p_75747_) {
this.layer = p_75745_;
this.chunkSource = p_75746_;
this.updatingSectionData = p_75747_;
this.visibleSectionData = p_75747_.copy();
this.visibleSectionData.disableCache();
this.sectionStates.defaultReturnValue((byte)0);
}
protected boolean storingLightForSection(long p_75792_) {
return this.getDataLayer(p_75792_, true) != null;
}
@Nullable
protected DataLayer getDataLayer(long p_75759_, boolean p_75760_) {
return this.getDataLayer(p_75760_ ? this.updatingSectionData : this.visibleSectionData, p_75759_);
}
@Nullable
protected DataLayer getDataLayer(M p_75762_, long p_75763_) {
return p_75762_.getLayer(p_75763_);
}
@Nullable
protected DataLayer getDataLayerToWrite(long p_285278_) {
DataLayer datalayer = this.updatingSectionData.getLayer(p_285278_);
if (datalayer == null) {
return null;
} else {
if (this.changedSections.add(p_285278_)) {
datalayer = datalayer.copy();
this.updatingSectionData.setLayer(p_285278_, datalayer);
this.updatingSectionData.clearCache();
}
return datalayer;
}
}
@Nullable
public DataLayer getDataLayerData(long p_75794_) {
DataLayer datalayer = this.queuedSections.get(p_75794_);
return datalayer != null ? datalayer : this.getDataLayer(p_75794_, false);
}
protected abstract int getLightValue(long p_75786_);
protected int getStoredLevel(long p_75796_) {
long i = SectionPos.blockToSection(p_75796_);
DataLayer datalayer = this.getDataLayer(i, true);
return datalayer.get(
SectionPos.sectionRelative(BlockPos.getX(p_75796_)),
SectionPos.sectionRelative(BlockPos.getY(p_75796_)),
SectionPos.sectionRelative(BlockPos.getZ(p_75796_))
);
}
protected void setStoredLevel(long p_75773_, int p_75774_) {
long i = SectionPos.blockToSection(p_75773_);
DataLayer datalayer;
if (this.changedSections.add(i)) {
datalayer = this.updatingSectionData.copyDataLayer(i);
} else {
datalayer = this.getDataLayer(i, true);
}
datalayer.set(
SectionPos.sectionRelative(BlockPos.getX(p_75773_)),
SectionPos.sectionRelative(BlockPos.getY(p_75773_)),
SectionPos.sectionRelative(BlockPos.getZ(p_75773_)),
p_75774_
);
SectionPos.aroundAndAtBlockPos(p_75773_, this.sectionsAffectedByLightUpdates::add);
}
protected void markSectionAndNeighborsAsAffected(long p_281610_) {
int i = SectionPos.x(p_281610_);
int j = SectionPos.y(p_281610_);
int k = SectionPos.z(p_281610_);
for (int l = -1; l <= 1; l++) {
for (int i1 = -1; i1 <= 1; i1++) {
for (int j1 = -1; j1 <= 1; j1++) {
this.sectionsAffectedByLightUpdates.add(SectionPos.asLong(i + i1, j + j1, k + l));
}
}
}
}
protected DataLayer createDataLayer(long p_75797_) {
DataLayer datalayer = this.queuedSections.get(p_75797_);
return datalayer != null ? datalayer : new DataLayer();
}
protected boolean hasInconsistencies() {
return this.hasInconsistencies;
}
protected void markNewInconsistencies(LightEngine<M, ?> p_285081_) {
if (this.hasInconsistencies) {
this.hasInconsistencies = false;
for (long i : this.toRemove) {
DataLayer datalayer = this.queuedSections.remove(i);
DataLayer datalayer1 = this.updatingSectionData.removeLayer(i);
if (this.columnsToRetainQueuedDataFor.contains(SectionPos.getZeroNode(i))) {
if (datalayer != null) {
this.queuedSections.put(i, datalayer);
} else if (datalayer1 != null) {
this.queuedSections.put(i, datalayer1);
}
}
}
this.updatingSectionData.clearCache();
for (long k : this.toRemove) {
this.onNodeRemoved(k);
this.changedSections.add(k);
}
this.toRemove.clear();
ObjectIterator<Entry<DataLayer>> objectiterator = Long2ObjectMaps.fastIterator(this.queuedSections);
while (objectiterator.hasNext()) {
Entry<DataLayer> entry = objectiterator.next();
long j = entry.getLongKey();
if (this.storingLightForSection(j)) {
DataLayer datalayer2 = entry.getValue();
if (this.updatingSectionData.getLayer(j) != datalayer2) {
this.updatingSectionData.setLayer(j, datalayer2);
this.changedSections.add(j);
}
objectiterator.remove();
}
}
this.updatingSectionData.clearCache();
}
}
protected void onNodeAdded(long p_75798_) {
}
protected void onNodeRemoved(long p_75799_) {
}
protected void setLightEnabled(long p_285065_, boolean p_284938_) {
if (p_284938_) {
this.columnsWithSources.add(p_285065_);
} else {
this.columnsWithSources.remove(p_285065_);
}
}
protected boolean lightOnInSection(long p_285433_) {
long i = SectionPos.getZeroNode(p_285433_);
return this.columnsWithSources.contains(i);
}
protected boolean lightOnInColumn(long p_370101_) {
return this.columnsWithSources.contains(p_370101_);
}
public void retainData(long p_75783_, boolean p_75784_) {
if (p_75784_) {
this.columnsToRetainQueuedDataFor.add(p_75783_);
} else {
this.columnsToRetainQueuedDataFor.remove(p_75783_);
}
}
protected void queueSectionData(long p_285403_, @Nullable DataLayer p_285498_) {
if (p_285498_ != null) {
this.queuedSections.put(p_285403_, p_285498_);
this.hasInconsistencies = true;
} else {
this.queuedSections.remove(p_285403_);
}
}
protected void updateSectionStatus(long p_75788_, boolean p_75789_) {
byte b0 = this.sectionStates.get(p_75788_);
byte b1 = LayerLightSectionStorage.SectionState.hasData(b0, !p_75789_);
if (b0 != b1) {
this.putSectionState(p_75788_, b1);
int i = p_75789_ ? -1 : 1;
for (int j = -1; j <= 1; j++) {
for (int k = -1; k <= 1; k++) {
for (int l = -1; l <= 1; l++) {
if (j != 0 || k != 0 || l != 0) {
long i1 = SectionPos.offset(p_75788_, j, k, l);
byte b2 = this.sectionStates.get(i1);
this.putSectionState(i1, LayerLightSectionStorage.SectionState.neighborCount(b2, LayerLightSectionStorage.SectionState.neighborCount(b2) + i));
}
}
}
}
}
}
protected void putSectionState(long p_285451_, byte p_285078_) {
if (p_285078_ != 0) {
if (this.sectionStates.put(p_285451_, p_285078_) == 0) {
this.initializeSection(p_285451_);
}
} else if (this.sectionStates.remove(p_285451_) != 0) {
this.removeSection(p_285451_);
}
}
private void initializeSection(long p_285124_) {
if (!this.toRemove.remove(p_285124_)) {
this.updatingSectionData.setLayer(p_285124_, this.createDataLayer(p_285124_));
this.changedSections.add(p_285124_);
this.onNodeAdded(p_285124_);
this.markSectionAndNeighborsAsAffected(p_285124_);
this.hasInconsistencies = true;
}
}
private void removeSection(long p_285477_) {
this.toRemove.add(p_285477_);
this.hasInconsistencies = true;
}
protected void swapSectionMap() {
if (!this.changedSections.isEmpty()) {
M m = this.updatingSectionData.copy();
m.disableCache();
this.visibleSectionData = m;
this.changedSections.clear();
}
if (!this.sectionsAffectedByLightUpdates.isEmpty()) {
LongIterator longiterator = this.sectionsAffectedByLightUpdates.iterator();
while (longiterator.hasNext()) {
long i = longiterator.nextLong();
this.chunkSource.onLightUpdate(this.layer, SectionPos.of(i));
}
this.sectionsAffectedByLightUpdates.clear();
}
}
public LayerLightSectionStorage.SectionType getDebugSectionType(long p_285114_) {
return LayerLightSectionStorage.SectionState.type(this.sectionStates.get(p_285114_));
}
protected static class SectionState {
public static final byte EMPTY = 0;
private static final int MIN_NEIGHBORS = 0;
private static final int MAX_NEIGHBORS = 26;
private static final byte HAS_DATA_BIT = 32;
private static final byte NEIGHBOR_COUNT_BITS = 31;
public static byte hasData(byte p_284954_, boolean p_285420_) {
return (byte)(p_285420_ ? p_284954_ | 32 : p_284954_ & -33);
}
public static byte neighborCount(byte p_285516_, int p_285426_) {
if (p_285426_ >= 0 && p_285426_ <= 26) {
return (byte)(p_285516_ & -32 | p_285426_ & 31);
} else {
throw new IllegalArgumentException("Neighbor count was not within range [0; 26]");
}
}
public static boolean hasData(byte p_285105_) {
return (p_285105_ & 32) != 0;
}
public static int neighborCount(byte p_285437_) {
return p_285437_ & 31;
}
public static LayerLightSectionStorage.SectionType type(byte p_285064_) {
if (p_285064_ == 0) {
return LayerLightSectionStorage.SectionType.EMPTY;
} else {
return hasData(p_285064_) ? LayerLightSectionStorage.SectionType.LIGHT_AND_DATA : LayerLightSectionStorage.SectionType.LIGHT_ONLY;
}
}
}
public static enum SectionType {
EMPTY("2"),
LIGHT_ONLY("1"),
LIGHT_AND_DATA("0");
private final String display;
private SectionType(final String p_285063_) {
this.display = p_285063_;
}
public String display() {
return this.display;
}
}
}