2021-05-31 02:05:41 +02:00
|
|
|
package com.jozufozu.flywheel.light;
|
2021-03-23 08:08:31 +01:00
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
import java.util.Set;
|
2021-04-08 19:22:11 +02:00
|
|
|
|
2021-05-11 20:02:43 +02:00
|
|
|
import com.jozufozu.flywheel.util.WeakHashSet;
|
2021-04-08 19:22:11 +02:00
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
|
|
|
import net.minecraft.client.Minecraft;
|
2021-03-23 08:08:31 +01:00
|
|
|
import net.minecraft.util.math.BlockPos;
|
|
|
|
import net.minecraft.util.math.SectionPos;
|
2021-03-24 14:54:24 +01:00
|
|
|
import net.minecraft.world.IBlockDisplayReader;
|
2021-03-23 08:08:31 +01:00
|
|
|
import net.minecraft.world.LightType;
|
|
|
|
|
|
|
|
public class LightUpdater {
|
|
|
|
|
|
|
|
private static LightUpdater instance;
|
|
|
|
|
|
|
|
public static LightUpdater getInstance() {
|
2021-06-30 21:43:54 +02:00
|
|
|
if (instance == null) instance = new LightUpdater();
|
2021-03-23 08:08:31 +01:00
|
|
|
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
private final WeakHashSet<ILightUpdateListener> allListeners;
|
|
|
|
private final WeakContainmentMultiMap<ILightUpdateListener> sections;
|
|
|
|
private final WeakContainmentMultiMap<ILightUpdateListener> chunks;
|
2021-03-23 08:08:31 +01:00
|
|
|
|
|
|
|
public LightUpdater() {
|
2021-08-29 23:40:46 +02:00
|
|
|
allListeners = new WeakHashSet<>();
|
|
|
|
sections = new WeakContainmentMultiMap<>();
|
|
|
|
chunks = new WeakContainmentMultiMap<>();
|
2021-03-23 08:08:31 +01:00
|
|
|
}
|
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
public void tick() {
|
|
|
|
for (ILightUpdateListener listener : allListeners) {
|
|
|
|
if (listener.status() == ListenerStatus.UPDATE) {
|
|
|
|
addListener(listener);
|
2021-03-23 08:08:31 +01:00
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
listener.onLightUpdate(Minecraft.getInstance().level, LightType.BLOCK, null);
|
|
|
|
}
|
|
|
|
}
|
2021-03-23 08:08:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-08-29 23:40:46 +02:00
|
|
|
* Add a listener.
|
|
|
|
|
2021-03-23 08:08:31 +01:00
|
|
|
* @param listener The object that wants to receive light update notifications.
|
|
|
|
*/
|
2021-08-29 23:40:46 +02:00
|
|
|
public void addListener(ILightUpdateListener listener) {
|
|
|
|
allListeners.add(listener);
|
|
|
|
|
|
|
|
Volume volume = listener.getVolume();
|
|
|
|
|
|
|
|
LongSet sections = this.sections.getAndResetContainment(listener);
|
|
|
|
LongSet chunks = this.chunks.getAndResetContainment(listener);
|
|
|
|
|
|
|
|
if (volume instanceof Volume.Block) {
|
|
|
|
BlockPos pos = ((Volume.Block) volume).pos;
|
|
|
|
long sectionPos = blockToSection(pos);
|
|
|
|
this.sections.put(sectionPos, listener);
|
|
|
|
sections.add(sectionPos);
|
|
|
|
|
|
|
|
long chunkPos = sectionToChunk(sectionPos);
|
|
|
|
this.chunks.put(chunkPos, listener);
|
|
|
|
chunks.add(chunkPos);
|
|
|
|
} else if (volume instanceof Volume.Box) {
|
|
|
|
GridAlignedBB box = ((Volume.Box) volume).box;
|
|
|
|
|
|
|
|
int minX = SectionPos.blockToSectionCoord(box.minX);
|
|
|
|
int minY = SectionPos.blockToSectionCoord(box.minY);
|
|
|
|
int minZ = SectionPos.blockToSectionCoord(box.minZ);
|
|
|
|
int maxX = SectionPos.blockToSectionCoord(box.maxX);
|
|
|
|
int maxY = SectionPos.blockToSectionCoord(box.maxY);
|
|
|
|
int maxZ = SectionPos.blockToSectionCoord(box.maxZ);
|
|
|
|
|
|
|
|
for (int x = minX; x <= maxX; x++) {
|
|
|
|
for (int z = minZ; z <= maxZ; z++) {
|
|
|
|
for (int y = minY; y <= maxY; y++) {
|
|
|
|
long sectionPos = SectionPos.asLong(x, y, z);
|
|
|
|
this.sections.put(sectionPos, listener);
|
|
|
|
sections.add(sectionPos);
|
|
|
|
}
|
|
|
|
long chunkPos = SectionPos.asLong(x, 0, z);
|
|
|
|
this.chunks.put(chunkPos, listener);
|
|
|
|
chunks.add(chunkPos);
|
2021-03-23 08:08:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-05-31 02:05:41 +02:00
|
|
|
* Dispatch light updates to all registered {@link ILightUpdateListener}s.
|
2021-03-23 08:08:31 +01:00
|
|
|
*
|
2021-04-30 02:19:08 +02:00
|
|
|
* @param world The world in which light was updated.
|
|
|
|
* @param type The type of light that changed.
|
2021-03-23 08:08:31 +01:00
|
|
|
* @param sectionPos A long representing the section position where light changed.
|
|
|
|
*/
|
2021-03-24 14:54:24 +01:00
|
|
|
public void onLightUpdate(IBlockDisplayReader world, LightType type, long sectionPos) {
|
2021-08-29 23:40:46 +02:00
|
|
|
Set<ILightUpdateListener> set = sections.get(sectionPos);
|
2021-03-23 08:08:31 +01:00
|
|
|
|
|
|
|
if (set == null || set.isEmpty()) return;
|
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
set.removeIf(l -> l.status().shouldRemove());
|
|
|
|
|
2021-07-15 20:36:24 +02:00
|
|
|
GridAlignedBB chunkBox = GridAlignedBB.from(SectionPos.of(sectionPos));
|
2021-03-23 08:08:31 +01:00
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
for (ILightUpdateListener listener : set) {
|
|
|
|
listener.onLightUpdate(world, type, chunkBox.copy());
|
|
|
|
}
|
2021-03-23 08:08:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-05-31 02:05:41 +02:00
|
|
|
* Dispatch light updates to all registered {@link ILightUpdateListener}s
|
2021-03-23 08:08:31 +01:00
|
|
|
* when the server sends lighting data for an entire chunk.
|
|
|
|
*
|
|
|
|
* @param world The world in which light was updated.
|
|
|
|
*/
|
2021-03-24 14:54:24 +01:00
|
|
|
public void onLightPacket(IBlockDisplayReader world, int chunkX, int chunkZ) {
|
2021-03-23 08:08:31 +01:00
|
|
|
long chunkPos = SectionPos.asLong(chunkX, 0, chunkZ);
|
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
Set<ILightUpdateListener> set = chunks.get(chunkPos);
|
2021-03-23 08:08:31 +01:00
|
|
|
|
|
|
|
if (set == null || set.isEmpty()) return;
|
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
set.removeIf(l -> l.status().shouldRemove());
|
2021-03-23 08:08:31 +01:00
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
for (ILightUpdateListener listener : set) {
|
|
|
|
listener.onLightPacket(world, chunkX, chunkZ);
|
2021-03-23 08:08:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-29 23:40:46 +02:00
|
|
|
public static long blockToSection(BlockPos pos) {
|
2021-03-23 08:08:31 +01:00
|
|
|
return SectionPos.asLong(pos.getX(), pos.getY(), pos.getZ());
|
|
|
|
}
|
|
|
|
|
|
|
|
public static long sectionToChunk(long sectionPos) {
|
|
|
|
return sectionPos & 0xFFFFFFFFFFF_00000L;
|
|
|
|
}
|
|
|
|
}
|