minecraft-source/src/net/minecraft/world/level/lighting/DynamicGraphMinFixedPoint.java

222 lines
8.4 KiB
Java

package net.minecraft.world.level.lighting;
import net.minecraft.util.Mth;
import it.unimi.dsi.fastutil.longs.LongList;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import java.util.function.LongPredicate;
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
public abstract class DynamicGraphMinFixedPoint {
private final int levelCount;
private final LongLinkedOpenHashSet[] queues;
private final Long2ByteMap computedLevels;
private int firstQueuedLevel;
private volatile boolean hasWork;
protected DynamicGraphMinFixedPoint(final int integer1, final int integer2, final int integer3) {
if (integer1 >= 254) {
throw new IllegalArgumentException("Level count must be < 254.");
}
this.levelCount = integer1;
this.queues = new LongLinkedOpenHashSet[integer1];
for (int integer4 = 0; integer4 < integer1; ++integer4) {
this.queues[integer4] = new LongLinkedOpenHashSet(integer2, 0.5f) {
protected void rehash(final int integer) {
if (integer > integer2) {
super.rehash(integer);
}
}
};
}
(this.computedLevels = (Long2ByteMap)new Long2ByteOpenHashMap(integer3, 0.5f) {
protected void rehash(final int integer) {
if (integer > integer3) {
super.rehash(integer);
}
}
}).defaultReturnValue((byte)(-1));
this.firstQueuedLevel = integer1;
}
private int getKey(final int integer1, final int integer2) {
int integer3 = integer1;
if (integer3 > integer2) {
integer3 = integer2;
}
if (integer3 > this.levelCount - 1) {
integer3 = this.levelCount - 1;
}
return integer3;
}
private void checkFirstQueuedLevel(final int integer) {
final int integer2 = this.firstQueuedLevel;
this.firstQueuedLevel = integer;
for (int integer3 = integer2 + 1; integer3 < integer; ++integer3) {
if (!this.queues[integer3].isEmpty()) {
this.firstQueuedLevel = integer3;
break;
}
}
}
protected void removeFromQueue(final long long1) {
final int integer4 = this.computedLevels.get(long1) & 0xFF;
if (integer4 == 255) {
return;
}
final int integer5 = this.getLevel(long1);
final int integer6 = this.getKey(integer5, integer4);
this.dequeue(long1, integer6, this.levelCount, true);
this.hasWork = (this.firstQueuedLevel < this.levelCount);
}
public void removeIf(final LongPredicate longPredicate) {
final LongList longList3 = (LongList)new LongArrayList(0);
final LongList list;
this.computedLevels.keySet().forEach(long3 -> {
if (longPredicate.test(long3)) {
list.add(long3);
}
return;
});
longList3.forEach(this::removeFromQueue);
}
private void dequeue(final long long1, final int integer2, final int integer3, final boolean boolean4) {
if (boolean4) {
this.computedLevels.remove(long1);
}
this.queues[integer2].remove(long1);
if (this.queues[integer2].isEmpty() && this.firstQueuedLevel == integer2) {
this.checkFirstQueuedLevel(integer3);
}
}
private void enqueue(final long long1, final int integer2, final int integer3) {
this.computedLevels.put(long1, (byte)integer2);
this.queues[integer3].add(long1);
if (this.firstQueuedLevel > integer3) {
this.firstQueuedLevel = integer3;
}
}
protected void checkNode(final long long1) {
this.checkEdge(long1, long1, this.levelCount - 1, false);
}
protected void checkEdge(final long long1, final long long2, final int integer, final boolean boolean4) {
this.checkEdge(long1, long2, integer, this.getLevel(long2), this.computedLevels.get(long2) & 0xFF, boolean4);
this.hasWork = (this.firstQueuedLevel < this.levelCount);
}
private void checkEdge(final long long1, final long long2, int integer3, int integer4, int integer5, final boolean boolean6) {
if (this.isSource(long2)) {
return;
}
integer3 = Mth.clamp(integer3, 0, this.levelCount - 1);
integer4 = Mth.clamp(integer4, 0, this.levelCount - 1);
boolean boolean7;
if (integer5 == 255) {
boolean7 = true;
integer5 = integer4;
}
else {
boolean7 = false;
}
int integer6;
if (boolean6) {
integer6 = Math.min(integer5, integer3);
}
else {
integer6 = Mth.clamp(this.getComputedLevel(long2, long1, integer3), 0, this.levelCount - 1);
}
final int integer7 = this.getKey(integer4, integer5);
if (integer4 != integer6) {
final int integer8 = this.getKey(integer4, integer6);
if (integer7 != integer8 && !boolean7) {
this.dequeue(long2, integer7, integer8, false);
}
this.enqueue(long2, integer6, integer8);
}
else if (!boolean7) {
this.dequeue(long2, integer7, this.levelCount, true);
}
}
protected final void checkNeighbor(final long long1, final long long2, final int integer, final boolean boolean4) {
final int integer2 = this.computedLevels.get(long2) & 0xFF;
final int integer3 = Mth.clamp(this.computeLevelFromNeighbor(long1, long2, integer), 0, this.levelCount - 1);
if (boolean4) {
this.checkEdge(long1, long2, integer3, this.getLevel(long2), integer2, true);
}
else {
boolean boolean5;
int integer4;
if (integer2 == 255) {
boolean5 = true;
integer4 = Mth.clamp(this.getLevel(long2), 0, this.levelCount - 1);
}
else {
integer4 = integer2;
boolean5 = false;
}
if (integer3 == integer4) {
this.checkEdge(long1, long2, this.levelCount - 1, boolean5 ? integer4 : this.getLevel(long2), integer2, false);
}
}
}
protected final boolean hasWork() {
return this.hasWork;
}
protected final int runUpdates(int integer) {
if (this.firstQueuedLevel >= this.levelCount) {
return integer;
}
while (this.firstQueuedLevel < this.levelCount && integer > 0) {
--integer;
final LongLinkedOpenHashSet longLinkedOpenHashSet3 = this.queues[this.firstQueuedLevel];
final long long4 = longLinkedOpenHashSet3.removeFirstLong();
final int integer2 = Mth.clamp(this.getLevel(long4), 0, this.levelCount - 1);
if (longLinkedOpenHashSet3.isEmpty()) {
this.checkFirstQueuedLevel(this.levelCount);
}
final int integer3 = this.computedLevels.remove(long4) & 0xFF;
if (integer3 < integer2) {
this.setLevel(long4, integer3);
this.checkNeighborsAfterUpdate(long4, integer3, true);
}
else {
if (integer3 <= integer2) {
continue;
}
this.enqueue(long4, integer3, this.getKey(this.levelCount - 1, integer3));
this.setLevel(long4, this.levelCount - 1);
this.checkNeighborsAfterUpdate(long4, integer2, false);
}
}
this.hasWork = (this.firstQueuedLevel < this.levelCount);
return integer;
}
public int getQueueSize() {
return this.computedLevels.size();
}
protected abstract boolean isSource(final long long1);
protected abstract int getComputedLevel(final long long1, final long long2, final int integer);
protected abstract void checkNeighborsAfterUpdate(final long long1, final int integer, final boolean boolean3);
protected abstract int getLevel(final long long1);
protected abstract void setLevel(final long long1, final int integer);
protected abstract int computeLevelFromNeighbor(final long long1, final long long2, final int integer);
}