222 lines
8.4 KiB
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);
|
|
}
|