mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-14 08:16:13 +01:00
Update light updates
- ... to address the nullpointer with create pulleys - LightListeners track their own levels - Remove BasicProvider and LightProvider - Rename MovingListener to better match functionality - Remove ListenerStatus in favor of a boolean - Instances keep track of their removal status and properly report it via LightListener#isListenerInvalid - Bump version - 0.6.4
This commit is contained in:
parent
f058b37b13
commit
055802160f
14 changed files with 112 additions and 147 deletions
|
@ -2,7 +2,7 @@ org.gradle.jvmargs = -Xmx3G
|
|||
org.gradle.daemon = false
|
||||
|
||||
# mod version info
|
||||
mod_version = 0.6.3
|
||||
mod_version = 0.6.4
|
||||
mc_update_version = 1.18
|
||||
minecraft_version = 1.18.2
|
||||
forge_version = 40.0.15
|
||||
|
|
|
@ -10,8 +10,6 @@ import com.jozufozu.flywheel.api.instance.TickableInstance;
|
|||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager;
|
||||
import com.jozufozu.flywheel.core.materials.FlatLit;
|
||||
import com.jozufozu.flywheel.light.LightListener;
|
||||
import com.jozufozu.flywheel.light.LightProvider;
|
||||
import com.jozufozu.flywheel.light.ListenerStatus;
|
||||
import com.jozufozu.flywheel.util.box.ImmutableBox;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -26,6 +24,7 @@ public abstract class AbstractInstance implements Instance, LightListener {
|
|||
|
||||
protected final MaterialManager materialManager;
|
||||
public final Level world;
|
||||
protected boolean removed = false;
|
||||
|
||||
public AbstractInstance(MaterialManager materialManager, Level world) {
|
||||
this.materialManager = materialManager;
|
||||
|
@ -39,10 +38,19 @@ public abstract class AbstractInstance implements Instance, LightListener {
|
|||
|
||||
}
|
||||
|
||||
final void removeAndMark() {
|
||||
if (removed) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove();
|
||||
removed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free any acquired resources.
|
||||
*/
|
||||
public abstract void remove();
|
||||
protected abstract void remove();
|
||||
|
||||
/**
|
||||
* Update instance data here. Good for when data doesn't change very often and when animations are GPU based.
|
||||
|
@ -78,12 +86,12 @@ public abstract class AbstractInstance implements Instance, LightListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ListenerStatus status() {
|
||||
return ListenerStatus.OKAY;
|
||||
public boolean isListenerInvalid() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLightUpdate(LightProvider world, LightLayer type, ImmutableBox changed) {
|
||||
public void onLightUpdate(LightLayer type, ImmutableBox changed) {
|
||||
updateLight();
|
||||
}
|
||||
|
||||
|
@ -103,4 +111,5 @@ public abstract class AbstractInstance implements Instance, LightListener {
|
|||
models.forEach(model -> model.setBlockLight(block)
|
||||
.setSkyLight(sky));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -260,7 +260,7 @@ public abstract class InstanceManager<T> implements InstancingEngine.OriginShift
|
|||
}
|
||||
|
||||
public void invalidate() {
|
||||
instances.values().forEach(AbstractInstance::remove);
|
||||
instances.values().forEach(AbstractInstance::removeAndMark);
|
||||
instances.clear();
|
||||
dynamicInstances.clear();
|
||||
tickableInstances.clear();
|
||||
|
@ -314,7 +314,7 @@ public abstract class InstanceManager<T> implements InstancingEngine.OriginShift
|
|||
}
|
||||
|
||||
protected void removeInternal(T obj, AbstractInstance instance) {
|
||||
instance.remove();
|
||||
instance.removeAndMark();
|
||||
instances.remove(obj);
|
||||
dynamicInstances.remove(obj);
|
||||
tickableInstances.remove(obj);
|
||||
|
|
|
@ -6,8 +6,7 @@ import com.jozufozu.flywheel.api.instance.TickableInstance;
|
|||
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager;
|
||||
import com.jozufozu.flywheel.light.LightListener;
|
||||
import com.jozufozu.flywheel.light.LightProvider;
|
||||
import com.jozufozu.flywheel.light.MovingListener;
|
||||
import com.jozufozu.flywheel.light.TickingLightListener;
|
||||
import com.jozufozu.flywheel.util.box.GridAlignedBB;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
|
@ -34,7 +33,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
*
|
||||
* @param <E> The type of {@link Entity} your class is an instance of.
|
||||
*/
|
||||
public abstract class EntityInstance<E extends Entity> extends AbstractInstance implements LightListener, MovingListener {
|
||||
public abstract class EntityInstance<E extends Entity> extends AbstractInstance implements LightListener, TickingLightListener {
|
||||
|
||||
protected final E entity;
|
||||
protected final GridAlignedBB bounds;
|
||||
|
@ -51,7 +50,7 @@ public abstract class EntityInstance<E extends Entity> extends AbstractInstance
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean update(LightProvider provider) {
|
||||
public boolean tickLightListener() {
|
||||
AABB boundsNow = entity.getBoundingBox();
|
||||
|
||||
if (bounds.sameAs(boundsNow)) return false;
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package com.jozufozu.flywheel.light;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
|
||||
/**
|
||||
* Wraps a world and minimally lowers the interface.
|
||||
*/
|
||||
public class BasicProvider implements LightProvider {
|
||||
|
||||
private final BlockAndTintGetter reader;
|
||||
private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
|
||||
public BasicProvider(BlockAndTintGetter reader) {
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLight(LightLayer type, int x, int y, int z) {
|
||||
return reader.getBrightness(type, pos.set(x, y, z));
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
|||
import com.jozufozu.flywheel.util.box.GridAlignedBB;
|
||||
import com.jozufozu.flywheel.util.box.ImmutableBox;
|
||||
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
|
||||
public class GPULightVolume extends LightVolume {
|
||||
|
@ -36,8 +37,8 @@ public class GPULightVolume extends LightVolume {
|
|||
private final GlTextureUnit textureUnit = GlTextureUnit.T4;
|
||||
protected boolean bufferDirty;
|
||||
|
||||
public GPULightVolume(ImmutableBox sampleVolume) {
|
||||
super(sampleVolume);
|
||||
public GPULightVolume(BlockAndTintGetter level, ImmutableBox sampleVolume) {
|
||||
super(level, sampleVolume);
|
||||
this.sampleVolume.assign(sampleVolume);
|
||||
|
||||
glTexture = new GlTexture(GL_TEXTURE_3D);
|
||||
|
@ -110,38 +111,24 @@ public class GPULightVolume extends LightVolume {
|
|||
glTexture.delete();
|
||||
}
|
||||
|
||||
public void move(LightProvider world, ImmutableBox newSampleVolume) {
|
||||
public void move(BlockAndTintGetter level, ImmutableBox newSampleVolume) {
|
||||
if (lightData == null) return;
|
||||
|
||||
if (box.contains(newSampleVolume)) {
|
||||
sampleVolume.assign(newSampleVolume);
|
||||
initialize(world);
|
||||
initialize();
|
||||
} else {
|
||||
super.move(world, newSampleVolume);
|
||||
super.move(level, newSampleVolume);
|
||||
}
|
||||
}
|
||||
|
||||
public void onLightUpdate(LightProvider world, LightLayer type, ImmutableBox changedVolume) {
|
||||
super.onLightUpdate(world, type, changedVolume);
|
||||
bufferDirty = true;
|
||||
}
|
||||
|
||||
public void onLightPacket(LightProvider world, int chunkX, int chunkZ) {
|
||||
super.onLightPacket(world, chunkX, chunkZ);
|
||||
bufferDirty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely (re)populate this volume with block and sky lighting data.
|
||||
* This is expensive and should be avoided.
|
||||
*/
|
||||
public void initialize(LightProvider world) {
|
||||
super.initialize(world);
|
||||
bufferDirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBox getVolume() {
|
||||
return sampleVolume;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void markDirty() {
|
||||
this.bufferDirty = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,26 +5,37 @@ import com.jozufozu.flywheel.util.box.ImmutableBox;
|
|||
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
|
||||
/**
|
||||
* Implementors of this interface may choose to subscribe to light updates by calling
|
||||
* {@link LightUpdater#addListener(LightListener)}.<p>
|
||||
*
|
||||
* It is the responsibility of the implementor to keep a reference to the level an object is contained in.
|
||||
*/
|
||||
public interface LightListener {
|
||||
|
||||
ImmutableBox getVolume();
|
||||
|
||||
ListenerStatus status();
|
||||
/**
|
||||
* Check the status of the light listener.
|
||||
* @return {@code true} if the listener is invalid/removed/deleted,
|
||||
* and should no longer receive updates.
|
||||
*/
|
||||
boolean isListenerInvalid();
|
||||
|
||||
/**
|
||||
* Called when a light updates in a chunk the implementor cares about.
|
||||
*/
|
||||
void onLightUpdate(LightProvider world, LightLayer type, ImmutableBox changed);
|
||||
void onLightUpdate(LightLayer type, ImmutableBox changed);
|
||||
|
||||
/**
|
||||
* Called when the server sends light data to the client.
|
||||
*
|
||||
*/
|
||||
default void onLightPacket(LightProvider world, int chunkX, int chunkZ) {
|
||||
default void onLightPacket(int chunkX, int chunkZ) {
|
||||
GridAlignedBB changedVolume = GridAlignedBB.from(chunkX, chunkZ);
|
||||
|
||||
onLightUpdate(world, LightLayer.BLOCK, changedVolume);
|
||||
onLightUpdate(LightLayer.BLOCK, changedVolume);
|
||||
|
||||
onLightUpdate(world, LightLayer.SKY, changedVolume);
|
||||
onLightUpdate(LightLayer.SKY, changedVolume);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package com.jozufozu.flywheel.light;
|
||||
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
|
||||
public interface LightProvider {
|
||||
int getLight(LightLayer type, int x, int y, int z);
|
||||
|
||||
default int getPackedLight(int x, int y, int z) {
|
||||
return LightTexture.pack(getLight(LightLayer.BLOCK, x, y, z), getLight(LightLayer.SKY, x, y, z));
|
||||
}
|
||||
}
|
|
@ -39,19 +39,15 @@ public class LightUpdater {
|
|||
}
|
||||
}
|
||||
|
||||
private final LightProvider provider;
|
||||
private final LevelAccessor level;
|
||||
|
||||
private final WeakHashSet<MovingListener> movingListeners = new WeakHashSet<>();
|
||||
private final WeakHashSet<TickingLightListener> tickingLightListeners = new WeakHashSet<>();
|
||||
private final WeakContainmentMultiMap<LightListener> sections = new WeakContainmentMultiMap<>();
|
||||
private final WeakContainmentMultiMap<LightListener> chunks = new WeakContainmentMultiMap<>();
|
||||
|
||||
public LightUpdater(LevelAccessor world) {
|
||||
public LightUpdater(LevelAccessor level) {
|
||||
taskEngine = Backend.getTaskEngine();
|
||||
provider = new BasicProvider(world);
|
||||
}
|
||||
|
||||
public LightProvider getProvider() {
|
||||
return provider;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
|
@ -60,9 +56,9 @@ public class LightUpdater {
|
|||
}
|
||||
|
||||
private void tickSerial() {
|
||||
for (MovingListener movingListener : movingListeners) {
|
||||
if (movingListener.update(provider)) {
|
||||
addListener(movingListener);
|
||||
for (TickingLightListener tickingLightListener : tickingLightListeners) {
|
||||
if (tickingLightListener.tickLightListener()) {
|
||||
addListener(tickingLightListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +67,8 @@ public class LightUpdater {
|
|||
Queue<LightListener> listeners = new ConcurrentLinkedQueue<>();
|
||||
|
||||
taskEngine.group("LightUpdater")
|
||||
.addTasks(movingListeners.stream(), listener -> {
|
||||
if (listener.update(provider)) {
|
||||
.addTasks(tickingLightListeners.stream(), listener -> {
|
||||
if (listener.tickLightListener()) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
})
|
||||
|
@ -86,8 +82,8 @@ public class LightUpdater {
|
|||
* @param listener The object that wants to receive light update notifications.
|
||||
*/
|
||||
public void addListener(LightListener listener) {
|
||||
if (listener instanceof MovingListener)
|
||||
movingListeners.add(((MovingListener) listener));
|
||||
if (listener instanceof TickingLightListener)
|
||||
tickingLightListeners.add(((TickingLightListener) listener));
|
||||
|
||||
ImmutableBox box = listener.getVolume();
|
||||
|
||||
|
@ -130,12 +126,12 @@ public class LightUpdater {
|
|||
|
||||
if (set == null || set.isEmpty()) return;
|
||||
|
||||
set.removeIf(l -> l.status().shouldRemove());
|
||||
set.removeIf(LightListener::isListenerInvalid);
|
||||
|
||||
ImmutableBox chunkBox = GridAlignedBB.from(SectionPos.of(sectionPos));
|
||||
|
||||
for (LightListener listener : set) {
|
||||
listener.onLightUpdate(provider, type, chunkBox);
|
||||
listener.onLightUpdate(type, chunkBox);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,10 +147,10 @@ public class LightUpdater {
|
|||
|
||||
if (set == null || set.isEmpty()) return;
|
||||
|
||||
set.removeIf(l -> l.status().shouldRemove());
|
||||
set.removeIf(LightListener::isListenerInvalid);
|
||||
|
||||
for (LightListener listener : set) {
|
||||
listener.onLightPacket(provider, chunkX, chunkZ);
|
||||
listener.onLightPacket(chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,14 +8,17 @@ import com.jozufozu.flywheel.util.box.GridAlignedBB;
|
|||
import com.jozufozu.flywheel.util.box.ImmutableBox;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
|
||||
public class LightVolume implements ImmutableBox, LightListener {
|
||||
|
||||
protected final BlockAndTintGetter level;
|
||||
protected final GridAlignedBB box = new GridAlignedBB();
|
||||
protected ByteBuffer lightData;
|
||||
|
||||
public LightVolume(ImmutableBox sampleVolume) {
|
||||
public LightVolume(BlockAndTintGetter level, ImmutableBox sampleVolume) {
|
||||
this.level = level;
|
||||
this.setBox(sampleVolume);
|
||||
|
||||
this.lightData = MemoryUtil.memAlloc(this.box.volume() * 2);
|
||||
|
@ -57,7 +60,7 @@ public class LightVolume implements ImmutableBox, LightListener {
|
|||
return box.getMaxZ();
|
||||
}
|
||||
|
||||
public void move(LightProvider world, ImmutableBox newSampleVolume) {
|
||||
public void move(BlockAndTintGetter level, ImmutableBox newSampleVolume) {
|
||||
if (lightData == null) return;
|
||||
|
||||
setBox(newSampleVolume);
|
||||
|
@ -65,51 +68,43 @@ public class LightVolume implements ImmutableBox, LightListener {
|
|||
if (neededCapacity > lightData.capacity()) {
|
||||
lightData = MemoryUtil.memRealloc(lightData, neededCapacity);
|
||||
}
|
||||
initialize(world);
|
||||
initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLightUpdate(LightProvider world, LightLayer type, ImmutableBox changedVolume) {
|
||||
public void onLightUpdate(LightLayer type, ImmutableBox changedVolume) {
|
||||
if (lightData == null) return;
|
||||
|
||||
GridAlignedBB vol = changedVolume.copy();
|
||||
if (!vol.intersects(getVolume())) return;
|
||||
vol.intersectAssign(getVolume()); // compute the region contained by us that has dirty lighting data.
|
||||
|
||||
if (type == LightLayer.BLOCK) copyBlock(world, vol);
|
||||
else if (type == LightLayer.SKY) copySky(world, vol);
|
||||
if (type == LightLayer.BLOCK) copyBlock(vol);
|
||||
else if (type == LightLayer.SKY) copySky(vol);
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLightPacket(LightProvider world, int chunkX, int chunkZ) {
|
||||
public void onLightPacket(int chunkX, int chunkZ) {
|
||||
if (lightData == null) return;
|
||||
|
||||
GridAlignedBB changedVolume = GridAlignedBB.from(chunkX, chunkZ);
|
||||
if (!changedVolume.intersects(getVolume())) return;
|
||||
changedVolume.intersectAssign(getVolume()); // compute the region contained by us that has dirty lighting data.
|
||||
|
||||
copyLight(world, changedVolume);
|
||||
copyLight(changedVolume);
|
||||
markDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely (re)populate this volume with block and sky lighting data.
|
||||
* This is expensive and should be avoided.
|
||||
*/
|
||||
public void initialize(LightProvider world) {
|
||||
public void initialize() {
|
||||
if (lightData == null) return;
|
||||
|
||||
// the volume is indexed based on the greater bounding box
|
||||
int shiftX = box.getMinX();
|
||||
int shiftY = box.getMinY();
|
||||
int shiftZ = box.getMinZ();
|
||||
|
||||
// ... but we only iterate over the (potentially) smaller sample volume
|
||||
getVolume().forEachContained((x, y, z) -> {
|
||||
int blockLight = world.getLight(LightLayer.BLOCK, x, y, z);
|
||||
int skyLight = world.getLight(LightLayer.SKY, x, y, z);
|
||||
|
||||
writeLight(x - shiftX, y - shiftY, z - shiftZ, blockLight, skyLight);
|
||||
});
|
||||
copyLight(getVolume());
|
||||
markDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,13 +112,15 @@ public class LightVolume implements ImmutableBox, LightListener {
|
|||
*
|
||||
* @param worldVolume the region in the world to copy data from.
|
||||
*/
|
||||
public void copyBlock(LightProvider world, ImmutableBox worldVolume) {
|
||||
public void copyBlock(ImmutableBox worldVolume) {
|
||||
var pos = new BlockPos.MutableBlockPos();
|
||||
|
||||
int xShift = box.getMinX();
|
||||
int yShift = box.getMinY();
|
||||
int zShift = box.getMinZ();
|
||||
|
||||
worldVolume.forEachContained((x, y, z) -> {
|
||||
int light = world.getLight(LightLayer.BLOCK, x, y, z);
|
||||
int light = this.level.getBrightness(LightLayer.BLOCK, pos.set(x, y, z));
|
||||
|
||||
writeBlock(x - xShift, y - yShift, z - zShift, light);
|
||||
});
|
||||
|
@ -134,13 +131,15 @@ public class LightVolume implements ImmutableBox, LightListener {
|
|||
*
|
||||
* @param worldVolume the region in the world to copy data from.
|
||||
*/
|
||||
public void copySky(LightProvider world, ImmutableBox worldVolume) {
|
||||
public void copySky(ImmutableBox worldVolume) {
|
||||
var pos = new BlockPos.MutableBlockPos();
|
||||
|
||||
int xShift = box.getMinX();
|
||||
int yShift = box.getMinY();
|
||||
int zShift = box.getMinZ();
|
||||
|
||||
worldVolume.forEachContained((x, y, z) -> {
|
||||
int light = world.getLight(LightLayer.SKY, x, y, z);
|
||||
int light = this.level.getBrightness(LightLayer.SKY, pos.set(x, y, z));
|
||||
|
||||
writeSky(x - xShift, y - yShift, z - zShift, light);
|
||||
});
|
||||
|
@ -151,7 +150,7 @@ public class LightVolume implements ImmutableBox, LightListener {
|
|||
*
|
||||
* @param worldVolume the region in the world to copy data from.
|
||||
*/
|
||||
public void copyLight(LightProvider world, ImmutableBox worldVolume) {
|
||||
public void copyLight(ImmutableBox worldVolume) {
|
||||
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
|
||||
int xShift = box.getMinX();
|
||||
|
@ -161,8 +160,8 @@ public class LightVolume implements ImmutableBox, LightListener {
|
|||
worldVolume.forEachContained((x, y, z) -> {
|
||||
pos.set(x, y, z);
|
||||
|
||||
int block = world.getLight(LightLayer.BLOCK, x, y, z);
|
||||
int sky = world.getLight(LightLayer.SKY, x, y, z);
|
||||
int block = this.level.getBrightness(LightLayer.BLOCK, pos);
|
||||
int sky = this.level.getBrightness(LightLayer.SKY, pos);
|
||||
|
||||
writeLight(x - xShift, y - yShift, z - zShift, block, sky);
|
||||
});
|
||||
|
@ -173,6 +172,10 @@ public class LightVolume implements ImmutableBox, LightListener {
|
|||
lightData = null;
|
||||
}
|
||||
|
||||
protected void markDirty() {
|
||||
// noop
|
||||
}
|
||||
|
||||
protected void writeLight(int x, int y, int z, int block, int sky) {
|
||||
byte b = (byte) ((block & 0xF) << 4);
|
||||
byte s = (byte) ((sky & 0xF) << 4);
|
||||
|
@ -211,8 +214,8 @@ public class LightVolume implements ImmutableBox, LightListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ListenerStatus status() {
|
||||
return ListenerStatus.OKAY;
|
||||
public boolean isListenerInvalid() {
|
||||
return lightData == null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package com.jozufozu.flywheel.light;
|
||||
|
||||
public enum ListenerStatus {
|
||||
OKAY,
|
||||
REMOVE,
|
||||
UPDATE,
|
||||
;
|
||||
|
||||
public boolean isOk() {
|
||||
return this == OKAY;
|
||||
}
|
||||
|
||||
public boolean shouldRemove() {
|
||||
return this == REMOVE;
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package com.jozufozu.flywheel.light;
|
||||
|
||||
public interface MovingListener extends LightListener {
|
||||
boolean update(LightProvider provider);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.jozufozu.flywheel.light;
|
||||
|
||||
public interface TickingLightListener extends LightListener {
|
||||
/**
|
||||
* Called every tick for active listeners.
|
||||
* @return {@code true} if the listener changed.
|
||||
*/
|
||||
boolean tickLightListener();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.light;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
Loading…
Reference in a new issue