mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-24 14:06:29 +01:00
Implicitly initiated
- Pass partial tick to visualizers and Effect#visualize - Pass partial tick to LitVisual#updateLight - Remove Visual#init - Rename LitVisual#initLightSectionNotifier to setLightSectionNotifier - Add static utility methods to FlatLit - Remove relight methods from AbstractVisual and add specialized relight methods to AbstractBlockEntityVisual and AbstractEntityVisual to match how vanilla retrieves lightmaps - Rename AtomicBitset to AtomicBitSet
This commit is contained in:
parent
6017228f4a
commit
06a2788f9c
29 changed files with 212 additions and 227 deletions
|
@ -31,5 +31,6 @@ gradlePlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("dev.architectury.loom:dev.architectury.loom.gradle.plugin:1.6-SNAPSHOT")
|
// FIXME: This should not hard-code the Loom version.
|
||||||
|
implementation("dev.architectury.loom:dev.architectury.loom.gradle.plugin:1.6.397")
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,5 +16,5 @@ public interface Effect {
|
||||||
* @param ctx The visualization context.
|
* @param ctx The visualization context.
|
||||||
* @return An arbitrary EffectVisual.
|
* @return An arbitrary EffectVisual.
|
||||||
*/
|
*/
|
||||||
List<EffectVisual<?>> visualize(VisualizationContext ctx);
|
List<EffectVisual<?>> visualize(VisualizationContext ctx, float partialTick);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,16 +13,14 @@ import net.minecraft.core.SectionPos;
|
||||||
*/
|
*/
|
||||||
public interface LitVisual extends Visual {
|
public interface LitVisual extends Visual {
|
||||||
/**
|
/**
|
||||||
* Called when a section this visual is contained in receives a light update.
|
* Set the notifier object.
|
||||||
*
|
*
|
||||||
* <p>Even if multiple sections are updated at the same time, this method will only be called once.</p>
|
* <p>This method is only called once right after the visual
|
||||||
|
* is created and before {@link #collectLightSections}.</p>
|
||||||
*
|
*
|
||||||
* <p>The implementation is free to parallelize calls to this method, as well as execute the plan
|
* @param notifier The notifier.
|
||||||
* returned by {@link DynamicVisual#planFrame} simultaneously. It is safe to query/update light here,
|
|
||||||
* but you must ensure proper synchronization if you want to mutate anything outside this visual or
|
|
||||||
* anything that is also mutated within {@link DynamicVisual#planFrame}.</p>
|
|
||||||
*/
|
*/
|
||||||
void updateLight();
|
void setLightSectionNotifier(Notifier notifier);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect the sections that this visual is contained in.
|
* Collect the sections that this visual is contained in.
|
||||||
|
@ -36,14 +34,18 @@ public interface LitVisual extends Visual {
|
||||||
void collectLightSections(LongConsumer consumer);
|
void collectLightSections(LongConsumer consumer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the notifier object.
|
* Called when a section this visual is contained in receives a light update.
|
||||||
*
|
*
|
||||||
* <p>This method is only called once, upon visual creation,
|
* <p>Even if multiple sections are updated at the same time, this method will only be called once.</p>
|
||||||
* after {@link #init} and before {@link #collectLightSections}.</p>
|
|
||||||
*
|
*
|
||||||
* @param notifier The notifier.
|
* <p>The implementation is free to parallelize calls to this method, as well as execute the plan
|
||||||
|
* returned by {@link DynamicVisual#planFrame} simultaneously. It is safe to query/update light here,
|
||||||
|
* but you must ensure proper synchronization if you want to mutate anything outside this visual or
|
||||||
|
* anything that is also mutated within {@link DynamicVisual#planFrame}.</p>
|
||||||
|
*
|
||||||
|
* <p>This method not is invoked automatically after visual creation.</p>
|
||||||
*/
|
*/
|
||||||
void initLightSectionNotifier(Notifier notifier);
|
void updateLight(float partialTick);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A notifier object that can be used to indicate to the impl
|
* A notifier object that can be used to indicate to the impl
|
||||||
|
|
|
@ -8,13 +8,6 @@ package dev.engine_room.flywheel.api.visual;
|
||||||
* @see LitVisual
|
* @see LitVisual
|
||||||
*/
|
*/
|
||||||
public interface Visual {
|
public interface Visual {
|
||||||
/**
|
|
||||||
* Initialize instances here.
|
|
||||||
*
|
|
||||||
* <p>This method will be called exactly once upon visual creation.</p>
|
|
||||||
*/
|
|
||||||
void init(float partialTick);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update instances here.
|
* Update instances here.
|
||||||
*
|
*
|
||||||
|
|
|
@ -18,7 +18,7 @@ public interface BlockEntityVisualizer<T extends BlockEntity> {
|
||||||
* @param blockEntity The block entity to construct a visual for.
|
* @param blockEntity The block entity to construct a visual for.
|
||||||
* @return The visual.
|
* @return The visual.
|
||||||
*/
|
*/
|
||||||
List<BlockEntityVisual<? super T>> createVisual(VisualizationContext ctx, T blockEntity);
|
List<BlockEntityVisual<? super T>> createVisual(VisualizationContext ctx, T blockEntity, float partialTick);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given block entity should not be rendered with the vanilla {@link BlockEntityRenderer}.
|
* Checks if the given block entity should not be rendered with the vanilla {@link BlockEntityRenderer}.
|
||||||
|
|
|
@ -18,7 +18,7 @@ public interface EntityVisualizer<T extends Entity> {
|
||||||
* @param entity The entity to construct a visual for.
|
* @param entity The entity to construct a visual for.
|
||||||
* @return The visual.
|
* @return The visual.
|
||||||
*/
|
*/
|
||||||
List<EntityVisual<? super T>> createVisual(VisualizationContext ctx, T entity);
|
List<EntityVisual<? super T>> createVisual(VisualizationContext ctx, T entity, float partialTick);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given entity should not render with the vanilla {@link EntityRenderer}.
|
* Checks if the given entity should not render with the vanilla {@link EntityRenderer}.
|
||||||
|
|
|
@ -8,7 +8,7 @@ import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||||
import dev.engine_room.flywheel.lib.util.AtomicBitset;
|
import dev.engine_room.flywheel.lib.util.AtomicBitSet;
|
||||||
|
|
||||||
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I> {
|
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I> {
|
||||||
public final InstanceType<I> type;
|
public final InstanceType<I> type;
|
||||||
|
@ -19,8 +19,8 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
||||||
protected final ArrayList<I> instances = new ArrayList<>();
|
protected final ArrayList<I> instances = new ArrayList<>();
|
||||||
protected final ArrayList<InstanceHandleImpl> handles = new ArrayList<>();
|
protected final ArrayList<InstanceHandleImpl> handles = new ArrayList<>();
|
||||||
|
|
||||||
protected final AtomicBitset changed = new AtomicBitset();
|
protected final AtomicBitSet changed = new AtomicBitSet();
|
||||||
protected final AtomicBitset deleted = new AtomicBitset();
|
protected final AtomicBitSet deleted = new AtomicBitSet();
|
||||||
|
|
||||||
protected AbstractInstancer(InstanceType<I> type, Environment environment) {
|
protected AbstractInstancer(InstanceType<I> type, Environment environment) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
package dev.engine_room.flywheel.lib.instance;
|
package dev.engine_room.flywheel.lib.instance;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.lib.visual.AbstractVisual;
|
import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual;
|
||||||
|
import dev.engine_room.flywheel.lib.visual.AbstractEntityVisual;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface that implementors of {@link Instance} should also implement
|
* An interface that implementors of {@link Instance} should also implement if they wish to make use of
|
||||||
* if they wish to make use of the relighting utilities in {@link AbstractVisual}.
|
* {@link #relight} and the relighting utilities in {@link AbstractBlockEntityVisual} and {@link AbstractEntityVisual}.
|
||||||
*/
|
*/
|
||||||
public interface FlatLit extends Instance {
|
public interface FlatLit extends Instance {
|
||||||
/**
|
/**
|
||||||
|
@ -25,4 +31,34 @@ public interface FlatLit extends Instance {
|
||||||
default FlatLit light(int blockLight, int skyLight) {
|
default FlatLit light(int blockLight, int skyLight) {
|
||||||
return light(LightTexture.pack(blockLight, skyLight));
|
return light(LightTexture.pack(blockLight, skyLight));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void relight(int packedLight, @Nullable FlatLit... instances) {
|
||||||
|
for (FlatLit instance : instances) {
|
||||||
|
if (instance != null) {
|
||||||
|
instance.light(packedLight)
|
||||||
|
.handle()
|
||||||
|
.setChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void relight(int packedLight, Iterator<@Nullable FlatLit> instances) {
|
||||||
|
while (instances.hasNext()) {
|
||||||
|
FlatLit instance = instances.next();
|
||||||
|
|
||||||
|
if (instance != null) {
|
||||||
|
instance.light(packedLight)
|
||||||
|
.handle()
|
||||||
|
.setChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void relight(int packedLight, Iterable<@Nullable FlatLit> instances) {
|
||||||
|
relight(packedLight, instances.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void relight(int packedLight, Stream<@Nullable FlatLit> instances) {
|
||||||
|
relight(packedLight, instances.iterator());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
// https://github.com/Netflix/hollow/blob/master/hollow/src/main/java/com/netflix/hollow/core/memory/ThreadSafeBitSet.java
|
// https://github.com/Netflix/hollow/blob/master/hollow/src/main/java/com/netflix/hollow/core/memory/ThreadSafeBitSet.java
|
||||||
// Refactored to remove unused methods, deduplicate some code segments, and add extra functionality with #forEachSetSpan
|
// Refactored to remove unused methods, deduplicate some code segments, and add extra functionality with #forEachSetSpan
|
||||||
public class AtomicBitset {
|
public class AtomicBitSet {
|
||||||
// 1024 bits, 128 bytes, 16 longs per segment
|
// 1024 bits, 128 bytes, 16 longs per segment
|
||||||
public static final int DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS = 10;
|
public static final int DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS = 10;
|
||||||
|
|
||||||
|
@ -18,17 +18,17 @@ public class AtomicBitset {
|
||||||
private final int numLongsPerSegment;
|
private final int numLongsPerSegment;
|
||||||
private final int log2SegmentSize;
|
private final int log2SegmentSize;
|
||||||
private final int segmentMask;
|
private final int segmentMask;
|
||||||
private final AtomicReference<AtomicBitsetSegments> segments;
|
private final AtomicReference<AtomicBitSetSegments> segments;
|
||||||
|
|
||||||
public AtomicBitset() {
|
public AtomicBitSet() {
|
||||||
this(DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS);
|
this(DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AtomicBitset(int log2SegmentSizeInBits) {
|
public AtomicBitSet(int log2SegmentSizeInBits) {
|
||||||
this(log2SegmentSizeInBits, 0);
|
this(log2SegmentSizeInBits, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AtomicBitset(int log2SegmentSizeInBits, int numBitsToPreallocate) {
|
public AtomicBitSet(int log2SegmentSizeInBits, int numBitsToPreallocate) {
|
||||||
if (log2SegmentSizeInBits < 6) {
|
if (log2SegmentSizeInBits < 6) {
|
||||||
throw new IllegalArgumentException("Cannot specify fewer than 64 bits in each segment!");
|
throw new IllegalArgumentException("Cannot specify fewer than 64 bits in each segment!");
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ public class AtomicBitset {
|
||||||
long numBitsPerSegment = numLongsPerSegment * 64L;
|
long numBitsPerSegment = numLongsPerSegment * 64L;
|
||||||
int numSegmentsToPreallocate = numBitsToPreallocate == 0 ? 1 : (int) (((numBitsToPreallocate - 1) / numBitsPerSegment) + 1);
|
int numSegmentsToPreallocate = numBitsToPreallocate == 0 ? 1 : (int) (((numBitsToPreallocate - 1) / numBitsPerSegment) + 1);
|
||||||
|
|
||||||
segments = new AtomicReference<>(new AtomicBitsetSegments(numSegmentsToPreallocate, numLongsPerSegment));
|
segments = new AtomicReference<>(new AtomicBitSetSegments(numSegmentsToPreallocate, numLongsPerSegment));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(int position) {
|
public void set(int position) {
|
||||||
|
@ -251,7 +251,7 @@ public class AtomicBitset {
|
||||||
}
|
}
|
||||||
|
|
||||||
public long maxSetBit() {
|
public long maxSetBit() {
|
||||||
AtomicBitsetSegments segments = this.segments.get();
|
AtomicBitSetSegments segments = this.segments.get();
|
||||||
|
|
||||||
int segmentIdx = segments.numSegments() - 1;
|
int segmentIdx = segments.numSegments() - 1;
|
||||||
|
|
||||||
|
@ -273,7 +273,7 @@ public class AtomicBitset {
|
||||||
throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
|
throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicBitsetSegments segments = this.segments.get();
|
AtomicBitSetSegments segments = this.segments.get();
|
||||||
|
|
||||||
int segmentPosition = segmentIndexForPosition(fromIndex);
|
int segmentPosition = segmentIndexForPosition(fromIndex);
|
||||||
if (segmentPosition >= segments.numSegments()) {
|
if (segmentPosition >= segments.numSegments()) {
|
||||||
|
@ -309,7 +309,7 @@ public class AtomicBitset {
|
||||||
|
|
||||||
int segmentPosition = segmentIndexForPosition(fromIndex);
|
int segmentPosition = segmentIndexForPosition(fromIndex);
|
||||||
|
|
||||||
AtomicBitsetSegments segments = this.segments.get();
|
AtomicBitSetSegments segments = this.segments.get();
|
||||||
|
|
||||||
if (segmentPosition >= segments.numSegments()) {
|
if (segmentPosition >= segments.numSegments()) {
|
||||||
return fromIndex;
|
return fromIndex;
|
||||||
|
@ -352,7 +352,7 @@ public class AtomicBitset {
|
||||||
* @param consumer The consumer to accept each span.
|
* @param consumer The consumer to accept each span.
|
||||||
*/
|
*/
|
||||||
public void forEachSetSpan(BitSpanConsumer consumer) {
|
public void forEachSetSpan(BitSpanConsumer consumer) {
|
||||||
AtomicBitsetSegments segments = this.segments.get();
|
AtomicBitSetSegments segments = this.segments.get();
|
||||||
|
|
||||||
if (segments.cardinality() == 0) {
|
if (segments.cardinality() == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -415,7 +415,7 @@ public class AtomicBitset {
|
||||||
* Clear all bits to 0.
|
* Clear all bits to 0.
|
||||||
*/
|
*/
|
||||||
public void clear() {
|
public void clear() {
|
||||||
AtomicBitsetSegments segments = this.segments.get();
|
AtomicBitSetSegments segments = this.segments.get();
|
||||||
|
|
||||||
for (int i = 0; i < segments.numSegments(); i++) {
|
for (int i = 0; i < segments.numSegments(); i++) {
|
||||||
AtomicLongArray segment = segments.getSegment(i);
|
AtomicLongArray segment = segments.getSegment(i);
|
||||||
|
@ -478,13 +478,13 @@ public class AtomicBitset {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private AtomicBitsetSegments expandToFit(int segmentIndex) {
|
private AtomicBitSet.AtomicBitSetSegments expandToFit(int segmentIndex) {
|
||||||
AtomicBitsetSegments visibleSegments = segments.get();
|
AtomicBitSetSegments visibleSegments = segments.get();
|
||||||
|
|
||||||
while (visibleSegments.numSegments() <= segmentIndex) {
|
while (visibleSegments.numSegments() <= segmentIndex) {
|
||||||
// Thread safety: newVisibleSegments contains all of the segments from the currently visible segments, plus extra.
|
// Thread safety: newVisibleSegments contains all of the segments from the currently visible segments, plus extra.
|
||||||
// all of the segments in the currently visible segments are canonical and will not change.
|
// all of the segments in the currently visible segments are canonical and will not change.
|
||||||
AtomicBitsetSegments newVisibleSegments = new AtomicBitsetSegments(visibleSegments, segmentIndex + 1, numLongsPerSegment);
|
AtomicBitSetSegments newVisibleSegments = new AtomicBitSetSegments(visibleSegments, segmentIndex + 1, numLongsPerSegment);
|
||||||
|
|
||||||
// because we are using a compareAndSet, if this thread "wins the race" and successfully sets this variable, then the segments
|
// because we are using a compareAndSet, if this thread "wins the race" and successfully sets this variable, then the segments
|
||||||
// which are newly defined in newVisibleSegments become canonical.
|
// which are newly defined in newVisibleSegments become canonical.
|
||||||
|
@ -500,10 +500,10 @@ public class AtomicBitset {
|
||||||
return visibleSegments;
|
return visibleSegments;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class AtomicBitsetSegments {
|
private static class AtomicBitSetSegments {
|
||||||
private final AtomicLongArray[] segments;
|
private final AtomicLongArray[] segments;
|
||||||
|
|
||||||
private AtomicBitsetSegments(int numSegments, int segmentLength) {
|
private AtomicBitSetSegments(int numSegments, int segmentLength) {
|
||||||
AtomicLongArray[] segments = new AtomicLongArray[numSegments];
|
AtomicLongArray[] segments = new AtomicLongArray[numSegments];
|
||||||
|
|
||||||
for (int i = 0; i < numSegments; i++) {
|
for (int i = 0; i < numSegments; i++) {
|
||||||
|
@ -515,7 +515,7 @@ public class AtomicBitset {
|
||||||
this.segments = segments;
|
this.segments = segments;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AtomicBitsetSegments(AtomicBitsetSegments copyFrom, int numSegments, int segmentLength) {
|
private AtomicBitSetSegments(AtomicBitSetSegments copyFrom, int numSegments, int segmentLength) {
|
||||||
AtomicLongArray[] segments = new AtomicLongArray[numSegments];
|
AtomicLongArray[] segments = new AtomicLongArray[numSegments];
|
||||||
|
|
||||||
for (int i = 0; i < numSegments; i++) {
|
for (int i = 0; i < numSegments; i++) {
|
||||||
|
@ -550,7 +550,7 @@ public class AtomicBitset {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!(obj instanceof AtomicBitset other)) {
|
if (!(obj instanceof AtomicBitSet other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,8 +558,8 @@ public class AtomicBitset {
|
||||||
throw new IllegalArgumentException("Segment sizes must be the same");
|
throw new IllegalArgumentException("Segment sizes must be the same");
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicBitsetSegments thisSegments = this.segments.get();
|
AtomicBitSetSegments thisSegments = this.segments.get();
|
||||||
AtomicBitsetSegments otherSegments = other.segments.get();
|
AtomicBitSetSegments otherSegments = other.segments.get();
|
||||||
|
|
||||||
for (int i = 0; i < thisSegments.numSegments(); i++) {
|
for (int i = 0; i < thisSegments.numSegments(); i++) {
|
||||||
AtomicLongArray thisArray = thisSegments.getSegment(i);
|
AtomicLongArray thisArray = thisSegments.getSegment(i);
|
|
@ -11,7 +11,9 @@ import dev.engine_room.flywheel.api.visual.LitVisual;
|
||||||
import dev.engine_room.flywheel.api.visual.TickableVisual;
|
import dev.engine_room.flywheel.api.visual.TickableVisual;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualManager;
|
import dev.engine_room.flywheel.api.visualization.VisualManager;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||||
|
import dev.engine_room.flywheel.lib.instance.FlatLit;
|
||||||
import dev.engine_room.flywheel.lib.math.MoreMath;
|
import dev.engine_room.flywheel.lib.math.MoreMath;
|
||||||
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
@ -40,8 +42,8 @@ public abstract class AbstractBlockEntityVisual<T extends BlockEntity> extends A
|
||||||
@Nullable
|
@Nullable
|
||||||
protected LitVisual.Notifier notifier;
|
protected LitVisual.Notifier notifier;
|
||||||
|
|
||||||
public AbstractBlockEntityVisual(VisualizationContext ctx, T blockEntity) {
|
public AbstractBlockEntityVisual(VisualizationContext ctx, T blockEntity, float partialTick) {
|
||||||
super(ctx, blockEntity.getLevel());
|
super(ctx, blockEntity.getLevel(), partialTick);
|
||||||
this.blockEntity = blockEntity;
|
this.blockEntity = blockEntity;
|
||||||
this.pos = blockEntity.getBlockPos();
|
this.pos = blockEntity.getBlockPos();
|
||||||
this.blockState = blockEntity.getBlockState();
|
this.blockState = blockEntity.getBlockState();
|
||||||
|
@ -49,8 +51,8 @@ public abstract class AbstractBlockEntityVisual<T extends BlockEntity> extends A
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(float partialTick) {
|
public void setLightSectionNotifier(Notifier notifier) {
|
||||||
updateLight();
|
this.notifier = notifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -58,11 +60,6 @@ public abstract class AbstractBlockEntityVisual<T extends BlockEntity> extends A
|
||||||
consumer.accept(SectionPos.asLong(pos));
|
consumer.accept(SectionPos.asLong(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initLightSectionNotifier(Notifier notifier) {
|
|
||||||
this.notifier = notifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In order to accommodate for floating point precision errors at high coordinates,
|
* In order to accommodate for floating point precision errors at high coordinates,
|
||||||
* {@link VisualManager}s are allowed to arbitrarily adjust the origin, and
|
* {@link VisualManager}s are allowed to arbitrarily adjust the origin, and
|
||||||
|
@ -100,4 +97,12 @@ public abstract class AbstractBlockEntityVisual<T extends BlockEntity> extends A
|
||||||
return !context.limiter()
|
return !context.limiter()
|
||||||
.shouldUpdate(pos.distToCenterSqr(context.camera().getPosition()));
|
.shouldUpdate(pos.distToCenterSqr(context.camera().getPosition()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void relight(BlockPos pos, @Nullable FlatLit... instances) {
|
||||||
|
FlatLit.relight(LevelRenderer.getLightColor(level, pos), instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void relight(@Nullable FlatLit... instances) {
|
||||||
|
relight(pos, instances);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,12 @@ import dev.engine_room.flywheel.api.visual.EntityVisual;
|
||||||
import dev.engine_room.flywheel.api.visual.TickableVisual;
|
import dev.engine_room.flywheel.api.visual.TickableVisual;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
|
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
|
||||||
|
import dev.engine_room.flywheel.lib.instance.FlatLit;
|
||||||
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.LightLayer;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,16 +35,12 @@ public abstract class AbstractEntityVisual<T extends Entity> extends AbstractVis
|
||||||
protected final T entity;
|
protected final T entity;
|
||||||
protected final EntityVisibilityTester visibilityTester;
|
protected final EntityVisibilityTester visibilityTester;
|
||||||
|
|
||||||
public AbstractEntityVisual(VisualizationContext ctx, T entity) {
|
public AbstractEntityVisual(VisualizationContext ctx, T entity, float partialTick) {
|
||||||
super(ctx, entity.level());
|
super(ctx, entity.level(), partialTick);
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
visibilityTester = new EntityVisibilityTester(entity, ctx.renderOrigin(), 1.5f);
|
visibilityTester = new EntityVisibilityTester(entity, ctx.renderOrigin(), 1.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(float partialTick) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the distance squared between this visual and the given <em>level</em> position.
|
* Calculate the distance squared between this visual and the given <em>level</em> position.
|
||||||
*
|
*
|
||||||
|
@ -84,4 +84,12 @@ public abstract class AbstractEntityVisual<T extends Entity> extends AbstractVis
|
||||||
public boolean isVisible(FrustumIntersection frustum) {
|
public boolean isVisible(FrustumIntersection frustum) {
|
||||||
return entity.noCulling || visibilityTester.check(frustum);
|
return entity.noCulling || visibilityTester.check(frustum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void relight(float partialTick, FlatLit... instances) {
|
||||||
|
BlockPos pos = BlockPos.containing(entity.getLightProbePosition(partialTick));
|
||||||
|
int blockLight = entity.isOnFire() ? 15 : level.getBrightness(LightLayer.BLOCK, pos);
|
||||||
|
int skyLight = level.getBrightness(LightLayer.SKY, pos);
|
||||||
|
int light = LightTexture.pack(blockLight, skyLight);
|
||||||
|
FlatLit.relight(light, instances);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,10 @@
|
||||||
package dev.engine_room.flywheel.lib.visual;
|
package dev.engine_room.flywheel.lib.visual;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
||||||
import dev.engine_room.flywheel.api.visual.Visual;
|
import dev.engine_room.flywheel.api.visual.Visual;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||||
import dev.engine_room.flywheel.lib.instance.FlatLit;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LightLayer;
|
|
||||||
|
|
||||||
public abstract class AbstractVisual implements Visual {
|
public abstract class AbstractVisual implements Visual {
|
||||||
/**
|
/**
|
||||||
|
@ -27,7 +19,7 @@ public abstract class AbstractVisual implements Visual {
|
||||||
|
|
||||||
protected boolean deleted = false;
|
protected boolean deleted = false;
|
||||||
|
|
||||||
public AbstractVisual(VisualizationContext ctx, Level level) {
|
public AbstractVisual(VisualizationContext ctx, Level level, float partialTick) {
|
||||||
this.visualizationContext = ctx;
|
this.visualizationContext = ctx;
|
||||||
this.instancerProvider = ctx.instancerProvider();
|
this.instancerProvider = ctx.instancerProvider();
|
||||||
this.renderOrigin = ctx.renderOrigin();
|
this.renderOrigin = ctx.renderOrigin();
|
||||||
|
@ -49,46 +41,4 @@ public abstract class AbstractVisual implements Visual {
|
||||||
_delete();
|
_delete();
|
||||||
deleted = true;
|
deleted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void relight(BlockPos pos, @Nullable FlatLit... instances) {
|
|
||||||
relight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos), instances);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void relight(int block, int sky, @Nullable FlatLit... instances) {
|
|
||||||
for (FlatLit instance : instances) {
|
|
||||||
if (instance == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
instance.light(block, sky)
|
|
||||||
.handle()
|
|
||||||
.setChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void relight(BlockPos pos, Stream<? extends @Nullable FlatLit> instances) {
|
|
||||||
relight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos), instances);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void relight(int block, int sky, Stream<? extends @Nullable FlatLit> instances) {
|
|
||||||
instances.filter(Objects::nonNull)
|
|
||||||
.forEach(instance -> instance.light(block, sky)
|
|
||||||
.handle()
|
|
||||||
.setChanged());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void relight(BlockPos pos, Iterable<? extends @Nullable FlatLit> instances) {
|
|
||||||
relight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos), instances);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void relight(int block, int sky, Iterable<? extends @Nullable FlatLit> instances) {
|
|
||||||
for (FlatLit instance : instances) {
|
|
||||||
if (instance == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
instance.light(block, sky)
|
|
||||||
.handle()
|
|
||||||
.setChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,8 @@ public class SimpleBlockEntityVisualizer<T extends BlockEntity> implements Block
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BlockEntityVisual<? super T>> createVisual(VisualizationContext ctx, T blockEntity) {
|
public List<BlockEntityVisual<? super T>> createVisual(VisualizationContext ctx, T blockEntity, float partialTick) {
|
||||||
return List.of(visualFactory.create(ctx, blockEntity));
|
return List.of(visualFactory.create(ctx, blockEntity, partialTick));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,7 +46,7 @@ public class SimpleBlockEntityVisualizer<T extends BlockEntity> implements Block
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface Factory<T extends BlockEntity> {
|
public interface Factory<T extends BlockEntity> {
|
||||||
BlockEntityVisual<? super T> create(VisualizationContext ctx, T blockEntity);
|
BlockEntityVisual<? super T> create(VisualizationContext ctx, T blockEntity, float partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,8 +9,8 @@ import net.minecraft.world.entity.Entity;
|
||||||
public class SimpleEntityVisual<T extends Entity> extends AbstractEntityVisual<T> implements SimpleDynamicVisual {
|
public class SimpleEntityVisual<T extends Entity> extends AbstractEntityVisual<T> implements SimpleDynamicVisual {
|
||||||
protected final List<EntityComponent> components = new ArrayList<>();
|
protected final List<EntityComponent> components = new ArrayList<>();
|
||||||
|
|
||||||
public SimpleEntityVisual(VisualizationContext ctx, T entity) {
|
public SimpleEntityVisual(VisualizationContext ctx, T entity, float partialTick) {
|
||||||
super(ctx, entity);
|
super(ctx, entity, partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addComponent(EntityComponent component) {
|
public void addComponent(EntityComponent component) {
|
||||||
|
|
|
@ -24,8 +24,8 @@ public class SimpleEntityVisualizer<T extends Entity> implements EntityVisualize
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<EntityVisual<? super T>> createVisual(VisualizationContext ctx, T entity) {
|
public List<EntityVisual<? super T>> createVisual(VisualizationContext ctx, T entity, float partialTick) {
|
||||||
return List.of(visualFactory.create(ctx, entity));
|
return List.of(visualFactory.create(ctx, entity, partialTick));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,7 +46,7 @@ public class SimpleEntityVisualizer<T extends Entity> implements EntityVisualize
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface Factory<T extends Entity> {
|
public interface Factory<T extends Entity> {
|
||||||
EntityVisual<? super T> create(VisualizationContext ctx, T entity);
|
EntityVisual<? super T> create(VisualizationContext ctx, T entity, float partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -53,13 +53,13 @@ public class BlockEntityStorage extends Storage<BlockEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<? extends BlockEntityVisual<?>> createRaw(BlockEntity obj) {
|
protected List<? extends BlockEntityVisual<?>> createRaw(BlockEntity obj, float partialTick) {
|
||||||
var visualizer = VisualizationHelper.getVisualizer(obj);
|
var visualizer = VisualizationHelper.getVisualizer(obj);
|
||||||
if (visualizer == null) {
|
if (visualizer == null) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
var visualList = visualizer.createVisual(visualizationContextSupplier.get(), obj);
|
var visualList = visualizer.createVisual(visualizationContextSupplier.get(), obj, partialTick);
|
||||||
|
|
||||||
BlockPos blockPos = obj.getBlockPos();
|
BlockPos blockPos = obj.getBlockPos();
|
||||||
posLookup.put(blockPos.asLong(), visualList);
|
posLookup.put(blockPos.asLong(), visualList);
|
||||||
|
|
|
@ -14,8 +14,8 @@ public class EffectStorage extends Storage<Effect> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<? extends EffectVisual<?>> createRaw(Effect obj) {
|
protected List<? extends EffectVisual<?>> createRaw(Effect obj, float partialTick) {
|
||||||
return obj.visualize(visualizationContextSupplier.get());
|
return obj.visualize(visualizationContextSupplier.get(), partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,13 +16,13 @@ public class EntityStorage extends Storage<Entity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<? extends EntityVisual<?>> createRaw(Entity obj) {
|
protected List<? extends EntityVisual<?>> createRaw(Entity obj, float partialTick) {
|
||||||
var visualizer = VisualizationHelper.getVisualizer(obj);
|
var visualizer = VisualizationHelper.getVisualizer(obj);
|
||||||
if (visualizer == null) {
|
if (visualizer == null) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
return visualizer.createVisual(visualizationContextSupplier.get(), obj);
|
return visualizer.createVisual(visualizationContextSupplier.get(), obj, partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -51,11 +51,12 @@ public class LitVisualStorage {
|
||||||
});
|
});
|
||||||
|
|
||||||
long updateId = getNextUpdateId();
|
long updateId = getNextUpdateId();
|
||||||
|
Updater.Context updaterContext = new Updater.Context(updateId, context.partialTick());
|
||||||
|
|
||||||
for (long section : sectionsUpdatedThisFrame) {
|
for (long section : sectionsUpdatedThisFrame) {
|
||||||
var visuals = sections2Visuals.get(section);
|
var visuals = sections2Visuals.get(section);
|
||||||
if (visuals != null && !visuals.isEmpty()) {
|
if (visuals != null && !visuals.isEmpty()) {
|
||||||
taskExecutor.execute(() -> Distribute.tasks(taskExecutor, updateId, sync, visuals, Updater::updateLight));
|
taskExecutor.execute(() -> Distribute.tasks(taskExecutor, updaterContext, sync, visuals, Updater::updateLight));
|
||||||
} else {
|
} else {
|
||||||
sync.decrementAndEventuallyRun();
|
sync.decrementAndEventuallyRun();
|
||||||
}
|
}
|
||||||
|
@ -89,8 +90,8 @@ public class LitVisualStorage {
|
||||||
return visuals2Sections.isEmpty();
|
return visuals2Sections.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAndInitNotifier(LitVisual visual) {
|
public void setNotifierAndAdd(LitVisual visual) {
|
||||||
visual.initLightSectionNotifier(new LitVisualNotifierImpl(visual));
|
visual.setLightSectionNotifier(new LitVisualNotifierImpl(visual));
|
||||||
add(visual);
|
add(visual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,15 +169,15 @@ public class LitVisualStorage {
|
||||||
|
|
||||||
// Breaking this into 2 separate cases allows us to avoid the overhead of atomics in the common case.
|
// Breaking this into 2 separate cases allows us to avoid the overhead of atomics in the common case.
|
||||||
sealed interface Updater {
|
sealed interface Updater {
|
||||||
void updateLight(long updateId);
|
void updateLight(Context ctx);
|
||||||
|
|
||||||
LitVisual visual();
|
LitVisual visual();
|
||||||
|
|
||||||
// The visual is only in one section. In this case, we can just update the visual directly.
|
// The visual is only in one section. In this case, we can just update the visual directly.
|
||||||
record Simple(LitVisual visual) implements Updater {
|
record Simple(LitVisual visual) implements Updater {
|
||||||
@Override
|
@Override
|
||||||
public void updateLight(long updateId) {
|
public void updateLight(Context ctx) {
|
||||||
visual.updateLight();
|
visual.updateLight(ctx.partialTick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,14 +185,17 @@ public class LitVisualStorage {
|
||||||
// even when multiple sections it was contained in are updated at the same time.
|
// even when multiple sections it was contained in are updated at the same time.
|
||||||
record Synced(LitVisual visual, AtomicLong updateId) implements Updater {
|
record Synced(LitVisual visual, AtomicLong updateId) implements Updater {
|
||||||
@Override
|
@Override
|
||||||
public void updateLight(long updateId) {
|
public void updateLight(Context ctx) {
|
||||||
// Different update ID means we won, so we can update the visual.
|
// Different update ID means we won, so we can update the visual.
|
||||||
// Same update ID means another thread beat us to the update.
|
// Same update ID means another thread beat us to the update.
|
||||||
if (this.updateId.getAndSet(updateId) != updateId) {
|
if (this.updateId.getAndSet(ctx.updateId) != ctx.updateId) {
|
||||||
visual.updateLight();
|
visual.updateLight(ctx.partialTick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record Context(long updateId, float partialTick) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class LitVisualNotifierImpl implements LitVisual.Notifier {
|
private final class LitVisualNotifierImpl implements LitVisual.Notifier {
|
||||||
|
|
|
@ -81,14 +81,14 @@ public abstract class Storage<T> {
|
||||||
visuals.replaceAll((obj, visuals) -> {
|
visuals.replaceAll((obj, visuals) -> {
|
||||||
visuals.forEach(Visual::delete);
|
visuals.forEach(Visual::delete);
|
||||||
|
|
||||||
var out = createRaw(obj);
|
var out = createRaw(obj, partialTick);
|
||||||
|
|
||||||
if (out.isEmpty()) {
|
if (out.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Visual visual : out) {
|
for (Visual visual : out) {
|
||||||
setup(visual, partialTick);
|
setup(visual);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
@ -108,7 +108,7 @@ public abstract class Storage<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void create(T obj, float partialTick) {
|
private void create(T obj, float partialTick) {
|
||||||
var visuals = createRaw(obj);
|
var visuals = createRaw(obj, partialTick);
|
||||||
|
|
||||||
if (visuals.isEmpty()) {
|
if (visuals.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -116,11 +116,11 @@ public abstract class Storage<T> {
|
||||||
this.visuals.put(obj, visuals);
|
this.visuals.put(obj, visuals);
|
||||||
|
|
||||||
for (Visual visual : visuals) {
|
for (Visual visual : visuals) {
|
||||||
setup(visual, partialTick);
|
setup(visual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract List<? extends Visual> createRaw(T obj);
|
protected abstract List<? extends Visual> createRaw(T obj, float partialTick);
|
||||||
|
|
||||||
public Plan<DynamicVisual.Context> framePlan() {
|
public Plan<DynamicVisual.Context> framePlan() {
|
||||||
return NestedPlan.of(dynamicVisuals, litVisuals.plan(), ForEachPlan.of(() -> simpleDynamicVisuals, SimpleDynamicVisual::beginFrame));
|
return NestedPlan.of(dynamicVisuals, litVisuals.plan(), ForEachPlan.of(() -> simpleDynamicVisuals, SimpleDynamicVisual::beginFrame));
|
||||||
|
@ -134,9 +134,7 @@ public abstract class Storage<T> {
|
||||||
litVisuals.enqueueLightUpdateSection(section);
|
litVisuals.enqueueLightUpdateSection(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setup(Visual visual, float partialTick) {
|
private void setup(Visual visual) {
|
||||||
visual.init(partialTick);
|
|
||||||
|
|
||||||
if (visual instanceof TickableVisual tickable) {
|
if (visual instanceof TickableVisual tickable) {
|
||||||
if (visual instanceof SimpleTickableVisual simpleTickable) {
|
if (visual instanceof SimpleTickableVisual simpleTickable) {
|
||||||
simpleTickableVisuals.add(simpleTickable);
|
simpleTickableVisuals.add(simpleTickable);
|
||||||
|
@ -154,7 +152,7 @@ public abstract class Storage<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visual instanceof LitVisual lit) {
|
if (visual instanceof LitVisual lit) {
|
||||||
litVisuals.addAndInitNotifier(lit);
|
litVisuals.setNotifierAndAdd(lit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,24 +26,19 @@ public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> imple
|
||||||
return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.BELL, BellRenderer.BELL_RESOURCE_LOCATION.sprite(), "bell_body"), Materials.BELL);
|
return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.BELL, BellRenderer.BELL_RESOURCE_LOCATION.sprite(), "bell_body"), Materials.BELL);
|
||||||
});
|
});
|
||||||
|
|
||||||
private OrientedInstance bell;
|
private final OrientedInstance bell;
|
||||||
|
|
||||||
private boolean wasShaking = false;
|
private boolean wasShaking = false;
|
||||||
|
|
||||||
public BellVisual(VisualizationContext ctx, BellBlockEntity blockEntity) {
|
public BellVisual(VisualizationContext ctx, BellBlockEntity blockEntity, float partialTick) {
|
||||||
super(ctx, blockEntity);
|
super(ctx, blockEntity, partialTick);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(float partialTick) {
|
|
||||||
bell = createBellInstance().setPivot(0.5f, 0.75f, 0.5f)
|
bell = createBellInstance().setPivot(0.5f, 0.75f, 0.5f)
|
||||||
.setPosition(getVisualPosition());
|
.setPosition(getVisualPosition());
|
||||||
|
|
||||||
bell.setChanged();
|
bell.setChanged();
|
||||||
|
|
||||||
updateRotation(partialTick);
|
updateRotation(partialTick);
|
||||||
|
updateLight(partialTick);
|
||||||
super.init(partialTick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private OrientedInstance createBellInstance() {
|
private OrientedInstance createBellInstance() {
|
||||||
|
@ -81,8 +76,8 @@ public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> imple
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateLight() {
|
public void updateLight(float partialTick) {
|
||||||
relight(pos, bell);
|
relight(bell);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -51,22 +51,20 @@ public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends Abstrac
|
||||||
return new SingleMeshModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "lock"), Materials.CHEST);
|
return new SingleMeshModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "lock"), Materials.CHEST);
|
||||||
});
|
});
|
||||||
|
|
||||||
private OrientedInstance bottom;
|
private final OrientedInstance bottom;
|
||||||
private TransformedInstance lid;
|
private final TransformedInstance lid;
|
||||||
private TransformedInstance lock;
|
private final TransformedInstance lock;
|
||||||
|
|
||||||
|
private final ChestType chestType;
|
||||||
|
private final Float2FloatFunction lidProgress;
|
||||||
|
|
||||||
private ChestType chestType;
|
|
||||||
private final Quaternionf baseRotation = new Quaternionf();
|
private final Quaternionf baseRotation = new Quaternionf();
|
||||||
private Float2FloatFunction lidProgress;
|
|
||||||
|
|
||||||
private float lastProgress = Float.NaN;
|
private float lastProgress = Float.NaN;
|
||||||
|
|
||||||
public ChestVisual(VisualizationContext ctx, T blockEntity) {
|
public ChestVisual(VisualizationContext ctx, T blockEntity, float partialTick) {
|
||||||
super(ctx, blockEntity);
|
super(ctx, blockEntity, partialTick);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(float partialTick) {
|
|
||||||
chestType = blockState.hasProperty(ChestBlock.TYPE) ? blockState.getValue(ChestBlock.TYPE) : ChestType.SINGLE;
|
chestType = blockState.hasProperty(ChestBlock.TYPE) ? blockState.getValue(ChestBlock.TYPE) : ChestType.SINGLE;
|
||||||
Material texture = Sheets.chooseMaterial(blockEntity, chestType, isChristmas());
|
Material texture = Sheets.chooseMaterial(blockEntity, chestType, isChristmas());
|
||||||
|
|
||||||
|
@ -90,8 +88,7 @@ public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends Abstrac
|
||||||
bottom.setChanged();
|
bottom.setChanged();
|
||||||
|
|
||||||
applyLidTransform(lidProgress.get(partialTick));
|
applyLidTransform(lidProgress.get(partialTick));
|
||||||
|
updateLight(partialTick);
|
||||||
super.init(partialTick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private OrientedInstance createBottomInstance(Material texture) {
|
private OrientedInstance createBottomInstance(Material texture) {
|
||||||
|
@ -153,8 +150,8 @@ public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends Abstrac
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateLight() {
|
public void updateLight(float partialTick) {
|
||||||
relight(pos, bottom, lid, lock);
|
relight(bottom, lid, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -38,19 +38,32 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
|
||||||
public static final ModelHolder SPAWNER_BODY_MODEL = createBodyModelHolder(ModelLayers.SPAWNER_MINECART);
|
public static final ModelHolder SPAWNER_BODY_MODEL = createBodyModelHolder(ModelLayers.SPAWNER_MINECART);
|
||||||
public static final ModelHolder TNT_BODY_MODEL = createBodyModelHolder(ModelLayers.TNT_MINECART);
|
public static final ModelHolder TNT_BODY_MODEL = createBodyModelHolder(ModelLayers.TNT_MINECART);
|
||||||
|
|
||||||
private final ModelHolder bodyModel;
|
private final TransformedInstance body;
|
||||||
|
|
||||||
private TransformedInstance body;
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private TransformedInstance contents;
|
private TransformedInstance contents;
|
||||||
private BlockState blockState;
|
|
||||||
private boolean active;
|
private final ModelHolder bodyModel;
|
||||||
|
|
||||||
private final PoseStack stack = new PoseStack();
|
private final PoseStack stack = new PoseStack();
|
||||||
|
|
||||||
public MinecartVisual(VisualizationContext ctx, T entity, ModelHolder bodyModel) {
|
private BlockState blockState;
|
||||||
super(ctx, entity);
|
private boolean active;
|
||||||
|
|
||||||
|
public MinecartVisual(VisualizationContext ctx, T entity, float partialTick, ModelHolder bodyModel) {
|
||||||
|
super(ctx, entity, partialTick);
|
||||||
|
|
||||||
this.bodyModel = bodyModel;
|
this.bodyModel = bodyModel;
|
||||||
|
|
||||||
|
body = createBodyInstance();
|
||||||
|
blockState = entity.getDisplayBlockState();
|
||||||
|
contents = createContentsInstance();
|
||||||
|
|
||||||
|
addComponent(new ShadowComponent(visualizationContext, entity).radius(0.7f));
|
||||||
|
addComponent(new FireComponent(visualizationContext, entity));
|
||||||
|
addComponent(new HitboxComponent(visualizationContext, entity));
|
||||||
|
|
||||||
|
updateInstances(partialTick);
|
||||||
|
updateLight(partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ModelHolder createBodyModelHolder(ModelLayerLocation layer) {
|
private static ModelHolder createBodyModelHolder(ModelLayerLocation layer) {
|
||||||
|
@ -59,22 +72,6 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(float partialTick) {
|
|
||||||
addComponent(new ShadowComponent(visualizationContext, entity).radius(0.7f));
|
|
||||||
addComponent(new FireComponent(visualizationContext, entity));
|
|
||||||
addComponent(new HitboxComponent(visualizationContext, entity));
|
|
||||||
|
|
||||||
body = createBodyInstance();
|
|
||||||
blockState = entity.getDisplayBlockState();
|
|
||||||
contents = createContentsInstance();
|
|
||||||
|
|
||||||
updateInstances(partialTick);
|
|
||||||
updateLight();
|
|
||||||
|
|
||||||
super.init(partialTick);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TransformedInstance createBodyInstance() {
|
private TransformedInstance createBodyInstance() {
|
||||||
return instancerProvider.instancer(InstanceTypes.TRANSFORMED, bodyModel.get())
|
return instancerProvider.instancer(InstanceTypes.TRANSFORMED, bodyModel.get())
|
||||||
.createInstance();
|
.createInstance();
|
||||||
|
@ -110,8 +107,6 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
|
||||||
}
|
}
|
||||||
contents = createContentsInstance();
|
contents = createContentsInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLight();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -198,6 +193,9 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
|
||||||
stack.scale(-1.0F, -1.0F, 1.0F);
|
stack.scale(-1.0F, -1.0F, 1.0F);
|
||||||
body.setTransform(stack)
|
body.setTransform(stack)
|
||||||
.setChanged();
|
.setChanged();
|
||||||
|
|
||||||
|
// TODO: Use LitVisual if possible.
|
||||||
|
updateLight(partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateContents(TransformedInstance contents, PoseStack stack, float partialTick) {
|
protected void updateContents(TransformedInstance contents, PoseStack stack, float partialTick) {
|
||||||
|
@ -205,8 +203,8 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
|
||||||
.setChanged();
|
.setChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateLight() {
|
public void updateLight(float partialTick) {
|
||||||
relight(entity.blockPosition(), body, contents);
|
relight(partialTick, body, contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -34,19 +34,16 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
|
||||||
return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "lid"), Materials.SHULKER);
|
return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "lid"), Materials.SHULKER);
|
||||||
});
|
});
|
||||||
|
|
||||||
private TransformedInstance base;
|
private final TransformedInstance base;
|
||||||
private TransformedInstance lid;
|
private final TransformedInstance lid;
|
||||||
|
|
||||||
private final PoseStack stack = new PoseStack();
|
private final PoseStack stack = new PoseStack();
|
||||||
|
|
||||||
private float lastProgress = Float.NaN;
|
private float lastProgress = Float.NaN;
|
||||||
|
|
||||||
public ShulkerBoxVisual(VisualizationContext ctx, ShulkerBoxBlockEntity blockEntity) {
|
public ShulkerBoxVisual(VisualizationContext ctx, ShulkerBoxBlockEntity blockEntity, float partialTick) {
|
||||||
super(ctx, blockEntity);
|
super(ctx, blockEntity, partialTick);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(float partialTick) {
|
|
||||||
DyeColor color = blockEntity.getColor();
|
DyeColor color = blockEntity.getColor();
|
||||||
Material texture;
|
Material texture;
|
||||||
if (color == null) {
|
if (color == null) {
|
||||||
|
@ -67,12 +64,11 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
|
||||||
.translateY(-1);
|
.translateY(-1);
|
||||||
|
|
||||||
base = createBaseInstance(texture).setTransform(stack);
|
base = createBaseInstance(texture).setTransform(stack);
|
||||||
lid = createLidInstance(texture).setTransform(stack);
|
|
||||||
|
|
||||||
base.setChanged();
|
base.setChanged();
|
||||||
|
lid = createLidInstance(texture).setTransform(stack);
|
||||||
lid.setChanged();
|
lid.setChanged();
|
||||||
|
|
||||||
super.init(partialTick);
|
updateLight(partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TransformedInstance createBaseInstance(Material texture) {
|
private TransformedInstance createBaseInstance(Material texture) {
|
||||||
|
@ -119,8 +115,8 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateLight() {
|
public void updateLight(float partialTick) {
|
||||||
relight(pos, base, lid);
|
relight(base, lid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,8 +11,8 @@ import net.minecraft.world.entity.vehicle.MinecartTNT;
|
||||||
public class TntMinecartVisual<T extends MinecartTNT> extends MinecartVisual<T> {
|
public class TntMinecartVisual<T extends MinecartTNT> extends MinecartVisual<T> {
|
||||||
private static final int WHITE_OVERLAY = OverlayTexture.pack(OverlayTexture.u(1.0F), 10);
|
private static final int WHITE_OVERLAY = OverlayTexture.pack(OverlayTexture.u(1.0F), 10);
|
||||||
|
|
||||||
public TntMinecartVisual(VisualizationContext ctx, T entity) {
|
public TntMinecartVisual(VisualizationContext ctx, T entity, float partialTick) {
|
||||||
super(ctx, entity, TNT_BODY_MODEL);
|
super(ctx, entity, partialTick, TNT_BODY_MODEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -47,27 +47,27 @@ public class VanillaVisuals {
|
||||||
.apply();
|
.apply();
|
||||||
|
|
||||||
builder(EntityType.CHEST_MINECART)
|
builder(EntityType.CHEST_MINECART)
|
||||||
.factory((ctx, entity) -> new MinecartVisual<>(ctx, entity, MinecartVisual.CHEST_BODY_MODEL))
|
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.CHEST_BODY_MODEL))
|
||||||
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
||||||
.apply();
|
.apply();
|
||||||
builder(EntityType.COMMAND_BLOCK_MINECART)
|
builder(EntityType.COMMAND_BLOCK_MINECART)
|
||||||
.factory((ctx, entity) -> new MinecartVisual<>(ctx, entity, MinecartVisual.COMMAND_BLOCK_BODY_MODEL))
|
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.COMMAND_BLOCK_BODY_MODEL))
|
||||||
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
||||||
.apply();
|
.apply();
|
||||||
builder(EntityType.FURNACE_MINECART)
|
builder(EntityType.FURNACE_MINECART)
|
||||||
.factory((ctx, entity) -> new MinecartVisual<>(ctx, entity, MinecartVisual.FURNACE_BODY_MODEL))
|
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.FURNACE_BODY_MODEL))
|
||||||
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
||||||
.apply();
|
.apply();
|
||||||
builder(EntityType.HOPPER_MINECART)
|
builder(EntityType.HOPPER_MINECART)
|
||||||
.factory((ctx, entity) -> new MinecartVisual<>(ctx, entity, MinecartVisual.HOPPER_BODY_MODEL))
|
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.HOPPER_BODY_MODEL))
|
||||||
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
||||||
.apply();
|
.apply();
|
||||||
builder(EntityType.MINECART)
|
builder(EntityType.MINECART)
|
||||||
.factory((ctx, entity) -> new MinecartVisual<>(ctx, entity, MinecartVisual.STANDARD_BODY_MODEL))
|
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.STANDARD_BODY_MODEL))
|
||||||
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
||||||
.apply();
|
.apply();
|
||||||
builder(EntityType.SPAWNER_MINECART)
|
builder(EntityType.SPAWNER_MINECART)
|
||||||
.factory((ctx, entity) -> new MinecartVisual<>(ctx, entity, MinecartVisual.SPAWNER_BODY_MODEL))
|
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.SPAWNER_BODY_MODEL))
|
||||||
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
.skipVanillaRender(MinecartVisual::shouldSkipRender)
|
||||||
.apply();
|
.apply();
|
||||||
builder(EntityType.TNT_MINECART)
|
builder(EntityType.TNT_MINECART)
|
||||||
|
|
|
@ -7,9 +7,9 @@ public class TestAtomicBitset {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNextClearBit() {
|
void testNextClearBit() {
|
||||||
var segmentLength = 1 << AtomicBitset.DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS;
|
var segmentLength = 1 << AtomicBitSet.DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS;
|
||||||
var bitLength = 2 << AtomicBitset.DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS;
|
var bitLength = 2 << AtomicBitSet.DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS;
|
||||||
var bs = new AtomicBitset(AtomicBitset.DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS, bitLength);
|
var bs = new AtomicBitSet(AtomicBitSet.DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS, bitLength);
|
||||||
|
|
||||||
Assertions.assertEquals(0, bs.nextClearBit(0));
|
Assertions.assertEquals(0, bs.nextClearBit(0));
|
||||||
Assertions.assertEquals(1, bs.nextClearBit(1));
|
Assertions.assertEquals(1, bs.nextClearBit(1));
|
||||||
|
|
|
@ -19,7 +19,8 @@ forge_version_range = [47.0.0,)
|
||||||
|
|
||||||
# General build dependency versions
|
# General build dependency versions
|
||||||
java_version = 17
|
java_version = 17
|
||||||
arch_loom_version = 1.6-SNAPSHOT
|
# FIXME: This doesn't do anything.
|
||||||
|
# arch_loom_version = 1.6-SNAPSHOT
|
||||||
cursegradle_version = 1.4.0
|
cursegradle_version = 1.4.0
|
||||||
parchment_version = 2023.09.03
|
parchment_version = 2023.09.03
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,11 @@ pluginManagement {
|
||||||
maven("https://maven.parchmentmc.org")
|
maven("https://maven.parchmentmc.org")
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
// FIXME: This doesn't do anything. The actual version is always the one defined in buildSrc/build.gradle.kts.
|
||||||
val arch_loom_version: String by settings
|
// plugins {
|
||||||
id("dev.architectury.loom") version arch_loom_version
|
// val arch_loom_version: String by settings
|
||||||
}
|
// id("dev.architectury.loom") version arch_loom_version
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.name = "Flywheel"
|
rootProject.name = "Flywheel"
|
||||||
|
|
Loading…
Reference in a new issue