diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 4853b6a15..ea885f0e6 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -31,5 +31,6 @@ gradlePlugin { } 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") } diff --git a/common/src/api/java/dev/engine_room/flywheel/api/visual/Effect.java b/common/src/api/java/dev/engine_room/flywheel/api/visual/Effect.java index d75936c34..d3ed43cf2 100644 --- a/common/src/api/java/dev/engine_room/flywheel/api/visual/Effect.java +++ b/common/src/api/java/dev/engine_room/flywheel/api/visual/Effect.java @@ -16,5 +16,5 @@ public interface Effect { * @param ctx The visualization context. * @return An arbitrary EffectVisual. */ - List> visualize(VisualizationContext ctx); + List> visualize(VisualizationContext ctx, float partialTick); } diff --git a/common/src/api/java/dev/engine_room/flywheel/api/visual/LitVisual.java b/common/src/api/java/dev/engine_room/flywheel/api/visual/LitVisual.java index e5d983eb5..4f05e7687 100644 --- a/common/src/api/java/dev/engine_room/flywheel/api/visual/LitVisual.java +++ b/common/src/api/java/dev/engine_room/flywheel/api/visual/LitVisual.java @@ -13,16 +13,14 @@ import net.minecraft.core.SectionPos; */ public interface LitVisual extends Visual { /** - * Called when a section this visual is contained in receives a light update. + * Set the notifier object. * - *

Even if multiple sections are updated at the same time, this method will only be called once.

+ *

This method is only called once right after the visual + * is created and before {@link #collectLightSections}.

* - *

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}.

+ * @param notifier The notifier. */ - void updateLight(); + void setLightSectionNotifier(Notifier notifier); /** * Collect the sections that this visual is contained in. @@ -36,14 +34,18 @@ public interface LitVisual extends Visual { void collectLightSections(LongConsumer consumer); /** - * Set the notifier object. + * Called when a section this visual is contained in receives a light update. * - *

This method is only called once, upon visual creation, - * after {@link #init} and before {@link #collectLightSections}.

+ *

Even if multiple sections are updated at the same time, this method will only be called once.

* - * @param notifier The notifier. + *

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}.

+ * + *

This method not is invoked automatically after visual creation.

*/ - void initLightSectionNotifier(Notifier notifier); + void updateLight(float partialTick); /** * A notifier object that can be used to indicate to the impl diff --git a/common/src/api/java/dev/engine_room/flywheel/api/visual/Visual.java b/common/src/api/java/dev/engine_room/flywheel/api/visual/Visual.java index 7ecbe1cfd..4aed57f59 100644 --- a/common/src/api/java/dev/engine_room/flywheel/api/visual/Visual.java +++ b/common/src/api/java/dev/engine_room/flywheel/api/visual/Visual.java @@ -8,13 +8,6 @@ package dev.engine_room.flywheel.api.visual; * @see LitVisual */ public interface Visual { - /** - * Initialize instances here. - * - *

This method will be called exactly once upon visual creation.

- */ - void init(float partialTick); - /** * Update instances here. * diff --git a/common/src/api/java/dev/engine_room/flywheel/api/visualization/BlockEntityVisualizer.java b/common/src/api/java/dev/engine_room/flywheel/api/visualization/BlockEntityVisualizer.java index bf5c2085d..41b5f99e9 100644 --- a/common/src/api/java/dev/engine_room/flywheel/api/visualization/BlockEntityVisualizer.java +++ b/common/src/api/java/dev/engine_room/flywheel/api/visualization/BlockEntityVisualizer.java @@ -18,7 +18,7 @@ public interface BlockEntityVisualizer { * @param blockEntity The block entity to construct a visual for. * @return The visual. */ - List> createVisual(VisualizationContext ctx, T blockEntity); + List> createVisual(VisualizationContext ctx, T blockEntity, float partialTick); /** * Checks if the given block entity should not be rendered with the vanilla {@link BlockEntityRenderer}. diff --git a/common/src/api/java/dev/engine_room/flywheel/api/visualization/EntityVisualizer.java b/common/src/api/java/dev/engine_room/flywheel/api/visualization/EntityVisualizer.java index 2fb3d070d..9e398da27 100644 --- a/common/src/api/java/dev/engine_room/flywheel/api/visualization/EntityVisualizer.java +++ b/common/src/api/java/dev/engine_room/flywheel/api/visualization/EntityVisualizer.java @@ -18,7 +18,7 @@ public interface EntityVisualizer { * @param entity The entity to construct a visual for. * @return The visual. */ - List> createVisual(VisualizationContext ctx, T entity); + List> createVisual(VisualizationContext ctx, T entity, float partialTick); /** * Checks if the given entity should not render with the vanilla {@link EntityRenderer}. diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/AbstractInstancer.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/AbstractInstancer.java index 3ab8d28e1..56fbfcf9d 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/AbstractInstancer.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/AbstractInstancer.java @@ -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.Instancer; 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 implements Instancer { public final InstanceType type; @@ -19,8 +19,8 @@ public abstract class AbstractInstancer implements Instancer protected final ArrayList instances = new ArrayList<>(); protected final ArrayList handles = new ArrayList<>(); - protected final AtomicBitset changed = new AtomicBitset(); - protected final AtomicBitset deleted = new AtomicBitset(); + protected final AtomicBitSet changed = new AtomicBitSet(); + protected final AtomicBitSet deleted = new AtomicBitSet(); protected AbstractInstancer(InstanceType type, Environment environment) { this.type = type; diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/instance/FlatLit.java b/common/src/lib/java/dev/engine_room/flywheel/lib/instance/FlatLit.java index 11e774dc8..f9bb8a75e 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/instance/FlatLit.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/instance/FlatLit.java @@ -1,12 +1,18 @@ 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.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; /** - * An interface that implementors of {@link Instance} should also implement - * if they wish to make use of the relighting utilities in {@link AbstractVisual}. + * An interface that implementors of {@link Instance} should also implement if they wish to make use of + * {@link #relight} and the relighting utilities in {@link AbstractBlockEntityVisual} and {@link AbstractEntityVisual}. */ public interface FlatLit extends Instance { /** @@ -25,4 +31,34 @@ public interface FlatLit extends Instance { default FlatLit light(int blockLight, int 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()); + } } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/util/AtomicBitset.java b/common/src/lib/java/dev/engine_room/flywheel/lib/util/AtomicBitSet.java similarity index 93% rename from common/src/lib/java/dev/engine_room/flywheel/lib/util/AtomicBitset.java rename to common/src/lib/java/dev/engine_room/flywheel/lib/util/AtomicBitSet.java index ea59e846d..28532b70d 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/util/AtomicBitset.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/util/AtomicBitSet.java @@ -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 // 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 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 log2SegmentSize; private final int segmentMask; - private final AtomicReference segments; + private final AtomicReference segments; - public AtomicBitset() { + public AtomicBitSet() { this(DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS); } - public AtomicBitset(int log2SegmentSizeInBits) { + public AtomicBitSet(int log2SegmentSizeInBits) { this(log2SegmentSizeInBits, 0); } - public AtomicBitset(int log2SegmentSizeInBits, int numBitsToPreallocate) { + public AtomicBitSet(int log2SegmentSizeInBits, int numBitsToPreallocate) { if (log2SegmentSizeInBits < 6) { throw new IllegalArgumentException("Cannot specify fewer than 64 bits in each segment!"); } @@ -40,7 +40,7 @@ public class AtomicBitset { long numBitsPerSegment = numLongsPerSegment * 64L; 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) { @@ -251,7 +251,7 @@ public class AtomicBitset { } public long maxSetBit() { - AtomicBitsetSegments segments = this.segments.get(); + AtomicBitSetSegments segments = this.segments.get(); int segmentIdx = segments.numSegments() - 1; @@ -273,7 +273,7 @@ public class AtomicBitset { throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); } - AtomicBitsetSegments segments = this.segments.get(); + AtomicBitSetSegments segments = this.segments.get(); int segmentPosition = segmentIndexForPosition(fromIndex); if (segmentPosition >= segments.numSegments()) { @@ -309,7 +309,7 @@ public class AtomicBitset { int segmentPosition = segmentIndexForPosition(fromIndex); - AtomicBitsetSegments segments = this.segments.get(); + AtomicBitSetSegments segments = this.segments.get(); if (segmentPosition >= segments.numSegments()) { return fromIndex; @@ -352,7 +352,7 @@ public class AtomicBitset { * @param consumer The consumer to accept each span. */ public void forEachSetSpan(BitSpanConsumer consumer) { - AtomicBitsetSegments segments = this.segments.get(); + AtomicBitSetSegments segments = this.segments.get(); if (segments.cardinality() == 0) { return; @@ -415,7 +415,7 @@ public class AtomicBitset { * Clear all bits to 0. */ public void clear() { - AtomicBitsetSegments segments = this.segments.get(); + AtomicBitSetSegments segments = this.segments.get(); for (int i = 0; i < segments.numSegments(); i++) { AtomicLongArray segment = segments.getSegment(i); @@ -478,13 +478,13 @@ public class AtomicBitset { } @NotNull - private AtomicBitsetSegments expandToFit(int segmentIndex) { - AtomicBitsetSegments visibleSegments = segments.get(); + private AtomicBitSet.AtomicBitSetSegments expandToFit(int segmentIndex) { + AtomicBitSetSegments visibleSegments = segments.get(); while (visibleSegments.numSegments() <= segmentIndex) { // 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. - 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 // which are newly defined in newVisibleSegments become canonical. @@ -500,10 +500,10 @@ public class AtomicBitset { return visibleSegments; } - private static class AtomicBitsetSegments { + private static class AtomicBitSetSegments { private final AtomicLongArray[] segments; - private AtomicBitsetSegments(int numSegments, int segmentLength) { + private AtomicBitSetSegments(int numSegments, int segmentLength) { AtomicLongArray[] segments = new AtomicLongArray[numSegments]; for (int i = 0; i < numSegments; i++) { @@ -515,7 +515,7 @@ public class AtomicBitset { this.segments = segments; } - private AtomicBitsetSegments(AtomicBitsetSegments copyFrom, int numSegments, int segmentLength) { + private AtomicBitSetSegments(AtomicBitSetSegments copyFrom, int numSegments, int segmentLength) { AtomicLongArray[] segments = new AtomicLongArray[numSegments]; for (int i = 0; i < numSegments; i++) { @@ -550,7 +550,7 @@ public class AtomicBitset { @Override public boolean equals(Object obj) { - if (!(obj instanceof AtomicBitset other)) { + if (!(obj instanceof AtomicBitSet other)) { return false; } @@ -558,8 +558,8 @@ public class AtomicBitset { throw new IllegalArgumentException("Segment sizes must be the same"); } - AtomicBitsetSegments thisSegments = this.segments.get(); - AtomicBitsetSegments otherSegments = other.segments.get(); + AtomicBitSetSegments thisSegments = this.segments.get(); + AtomicBitSetSegments otherSegments = other.segments.get(); for (int i = 0; i < thisSegments.numSegments(); i++) { AtomicLongArray thisArray = thisSegments.getSegment(i); diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractBlockEntityVisual.java b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractBlockEntityVisual.java index bdecdb4c4..59722198e 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractBlockEntityVisual.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractBlockEntityVisual.java @@ -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.visualization.VisualManager; 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 net.minecraft.client.renderer.LevelRenderer; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.world.level.block.entity.BlockEntity; @@ -40,8 +42,8 @@ public abstract class AbstractBlockEntityVisual extends A @Nullable protected LitVisual.Notifier notifier; - public AbstractBlockEntityVisual(VisualizationContext ctx, T blockEntity) { - super(ctx, blockEntity.getLevel()); + public AbstractBlockEntityVisual(VisualizationContext ctx, T blockEntity, float partialTick) { + super(ctx, blockEntity.getLevel(), partialTick); this.blockEntity = blockEntity; this.pos = blockEntity.getBlockPos(); this.blockState = blockEntity.getBlockState(); @@ -49,8 +51,8 @@ public abstract class AbstractBlockEntityVisual extends A } @Override - public void init(float partialTick) { - updateLight(); + public void setLightSectionNotifier(Notifier notifier) { + this.notifier = notifier; } @Override @@ -58,11 +60,6 @@ public abstract class AbstractBlockEntityVisual extends A 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, * {@link VisualManager}s are allowed to arbitrarily adjust the origin, and @@ -100,4 +97,12 @@ public abstract class AbstractBlockEntityVisual extends A return !context.limiter() .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); + } } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractEntityVisual.java b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractEntityVisual.java index e675a63b4..0cff1c953 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractEntityVisual.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractEntityVisual.java @@ -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.visualization.VisualizationContext; 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.world.entity.Entity; +import net.minecraft.world.level.LightLayer; import net.minecraft.world.phys.Vec3; /** @@ -31,16 +35,12 @@ public abstract class AbstractEntityVisual extends AbstractVis protected final T entity; protected final EntityVisibilityTester visibilityTester; - public AbstractEntityVisual(VisualizationContext ctx, T entity) { - super(ctx, entity.level()); + public AbstractEntityVisual(VisualizationContext ctx, T entity, float partialTick) { + super(ctx, entity.level(), partialTick); this.entity = entity; visibilityTester = new EntityVisibilityTester(entity, ctx.renderOrigin(), 1.5f); } - @Override - public void init(float partialTick) { - } - /** * Calculate the distance squared between this visual and the given level position. * @@ -84,4 +84,12 @@ public abstract class AbstractEntityVisual extends AbstractVis public boolean isVisible(FrustumIntersection 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); + } } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractVisual.java b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractVisual.java index ce43eca96..c21866435 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractVisual.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/AbstractVisual.java @@ -1,18 +1,10 @@ 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.visual.Visual; 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.world.level.Level; -import net.minecraft.world.level.LightLayer; public abstract class AbstractVisual implements Visual { /** @@ -27,7 +19,7 @@ public abstract class AbstractVisual implements Visual { protected boolean deleted = false; - public AbstractVisual(VisualizationContext ctx, Level level) { + public AbstractVisual(VisualizationContext ctx, Level level, float partialTick) { this.visualizationContext = ctx; this.instancerProvider = ctx.instancerProvider(); this.renderOrigin = ctx.renderOrigin(); @@ -49,46 +41,4 @@ public abstract class AbstractVisual implements Visual { _delete(); 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 instances) { - relight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos), instances); - } - - protected void relight(int block, int sky, Stream instances) { - instances.filter(Objects::nonNull) - .forEach(instance -> instance.light(block, sky) - .handle() - .setChanged()); - } - - protected void relight(BlockPos pos, Iterable instances) { - relight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos), instances); - } - - protected void relight(int block, int sky, Iterable instances) { - for (FlatLit instance : instances) { - if (instance == null) { - continue; - } - instance.light(block, sky) - .handle() - .setChanged(); - } - } } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleBlockEntityVisualizer.java b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleBlockEntityVisualizer.java index 882202ad3..d3c302d45 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleBlockEntityVisualizer.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleBlockEntityVisualizer.java @@ -24,8 +24,8 @@ public class SimpleBlockEntityVisualizer implements Block } @Override - public List> createVisual(VisualizationContext ctx, T blockEntity) { - return List.of(visualFactory.create(ctx, blockEntity)); + public List> createVisual(VisualizationContext ctx, T blockEntity, float partialTick) { + return List.of(visualFactory.create(ctx, blockEntity, partialTick)); } @Override @@ -46,7 +46,7 @@ public class SimpleBlockEntityVisualizer implements Block @FunctionalInterface public interface Factory { - BlockEntityVisual create(VisualizationContext ctx, T blockEntity); + BlockEntityVisual create(VisualizationContext ctx, T blockEntity, float partialTick); } /** diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleEntityVisual.java b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleEntityVisual.java index 0af57ec5b..35bb8b3a5 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleEntityVisual.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleEntityVisual.java @@ -9,8 +9,8 @@ import net.minecraft.world.entity.Entity; public class SimpleEntityVisual extends AbstractEntityVisual implements SimpleDynamicVisual { protected final List components = new ArrayList<>(); - public SimpleEntityVisual(VisualizationContext ctx, T entity) { - super(ctx, entity); + public SimpleEntityVisual(VisualizationContext ctx, T entity, float partialTick) { + super(ctx, entity, partialTick); } public void addComponent(EntityComponent component) { diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleEntityVisualizer.java b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleEntityVisualizer.java index 980d8d835..4757dc6ff 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleEntityVisualizer.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/SimpleEntityVisualizer.java @@ -24,8 +24,8 @@ public class SimpleEntityVisualizer implements EntityVisualize } @Override - public List> createVisual(VisualizationContext ctx, T entity) { - return List.of(visualFactory.create(ctx, entity)); + public List> createVisual(VisualizationContext ctx, T entity, float partialTick) { + return List.of(visualFactory.create(ctx, entity, partialTick)); } @Override @@ -46,7 +46,7 @@ public class SimpleEntityVisualizer implements EntityVisualize @FunctionalInterface public interface Factory { - EntityVisual create(VisualizationContext ctx, T entity); + EntityVisual create(VisualizationContext ctx, T entity, float partialTick); } /** diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/BlockEntityStorage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/BlockEntityStorage.java index d43e65e6c..d89273dcc 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/BlockEntityStorage.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/BlockEntityStorage.java @@ -53,13 +53,13 @@ public class BlockEntityStorage extends Storage { } @Override - protected List> createRaw(BlockEntity obj) { + protected List> createRaw(BlockEntity obj, float partialTick) { var visualizer = VisualizationHelper.getVisualizer(obj); if (visualizer == null) { return List.of(); } - var visualList = visualizer.createVisual(visualizationContextSupplier.get(), obj); + var visualList = visualizer.createVisual(visualizationContextSupplier.get(), obj, partialTick); BlockPos blockPos = obj.getBlockPos(); posLookup.put(blockPos.asLong(), visualList); diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/EffectStorage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/EffectStorage.java index b25b383c9..a59ef7e85 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/EffectStorage.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/EffectStorage.java @@ -14,8 +14,8 @@ public class EffectStorage extends Storage { } @Override - protected List> createRaw(Effect obj) { - return obj.visualize(visualizationContextSupplier.get()); + protected List> createRaw(Effect obj, float partialTick) { + return obj.visualize(visualizationContextSupplier.get(), partialTick); } @Override diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/EntityStorage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/EntityStorage.java index c0e269d5a..eed2e0f2d 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/EntityStorage.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/manager/EntityStorage.java @@ -16,13 +16,13 @@ public class EntityStorage extends Storage { } @Override - protected List> createRaw(Entity obj) { + protected List> createRaw(Entity obj, float partialTick) { var visualizer = VisualizationHelper.getVisualizer(obj); if (visualizer == null) { return List.of(); } - return visualizer.createVisual(visualizationContextSupplier.get(), obj); + return visualizer.createVisual(visualizationContextSupplier.get(), obj, partialTick); } @Override diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LitVisualStorage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LitVisualStorage.java index 884a5f759..3651fe278 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LitVisualStorage.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/LitVisualStorage.java @@ -51,11 +51,12 @@ public class LitVisualStorage { }); long updateId = getNextUpdateId(); + Updater.Context updaterContext = new Updater.Context(updateId, context.partialTick()); for (long section : sectionsUpdatedThisFrame) { var visuals = sections2Visuals.get(section); 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 { sync.decrementAndEventuallyRun(); } @@ -89,8 +90,8 @@ public class LitVisualStorage { return visuals2Sections.isEmpty(); } - public void addAndInitNotifier(LitVisual visual) { - visual.initLightSectionNotifier(new LitVisualNotifierImpl(visual)); + public void setNotifierAndAdd(LitVisual visual) { + visual.setLightSectionNotifier(new LitVisualNotifierImpl(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. sealed interface Updater { - void updateLight(long updateId); + void updateLight(Context ctx); LitVisual visual(); // The visual is only in one section. In this case, we can just update the visual directly. record Simple(LitVisual visual) implements Updater { @Override - public void updateLight(long updateId) { - visual.updateLight(); + public void updateLight(Context ctx) { + 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. record Synced(LitVisual visual, AtomicLong updateId) implements Updater { @Override - public void updateLight(long updateId) { + public void updateLight(Context ctx) { // Different update ID means we won, so we can update the visual. // Same update ID means another thread beat us to the update. - if (this.updateId.getAndSet(updateId) != updateId) { - visual.updateLight(); + if (this.updateId.getAndSet(ctx.updateId) != ctx.updateId) { + visual.updateLight(ctx.partialTick); } } } + + record Context(long updateId, float partialTick) { + } } private final class LitVisualNotifierImpl implements LitVisual.Notifier { diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/Storage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/Storage.java index c81298150..58c8ce42b 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/Storage.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/Storage.java @@ -81,14 +81,14 @@ public abstract class Storage { visuals.replaceAll((obj, visuals) -> { visuals.forEach(Visual::delete); - var out = createRaw(obj); + var out = createRaw(obj, partialTick); if (out.isEmpty()) { return null; } for (Visual visual : out) { - setup(visual, partialTick); + setup(visual); } return out; @@ -108,7 +108,7 @@ public abstract class Storage { } private void create(T obj, float partialTick) { - var visuals = createRaw(obj); + var visuals = createRaw(obj, partialTick); if (visuals.isEmpty()) { return; @@ -116,11 +116,11 @@ public abstract class Storage { this.visuals.put(obj, visuals); for (Visual visual : visuals) { - setup(visual, partialTick); + setup(visual); } } - protected abstract List createRaw(T obj); + protected abstract List createRaw(T obj, float partialTick); public Plan framePlan() { return NestedPlan.of(dynamicVisuals, litVisuals.plan(), ForEachPlan.of(() -> simpleDynamicVisuals, SimpleDynamicVisual::beginFrame)); @@ -134,9 +134,7 @@ public abstract class Storage { litVisuals.enqueueLightUpdateSection(section); } - private void setup(Visual visual, float partialTick) { - visual.init(partialTick); - + private void setup(Visual visual) { if (visual instanceof TickableVisual tickable) { if (visual instanceof SimpleTickableVisual simpleTickable) { simpleTickableVisuals.add(simpleTickable); @@ -154,7 +152,7 @@ public abstract class Storage { } if (visual instanceof LitVisual lit) { - litVisuals.addAndInitNotifier(lit); + litVisuals.setNotifierAndAdd(lit); } } diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/BellVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/BellVisual.java index 12ae9fcd4..9a81b2ae4 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/BellVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/BellVisual.java @@ -26,24 +26,19 @@ public class BellVisual extends AbstractBlockEntityVisual imple 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; - public BellVisual(VisualizationContext ctx, BellBlockEntity blockEntity) { - super(ctx, blockEntity); - } + public BellVisual(VisualizationContext ctx, BellBlockEntity blockEntity, float partialTick) { + super(ctx, blockEntity, partialTick); - @Override - public void init(float partialTick) { bell = createBellInstance().setPivot(0.5f, 0.75f, 0.5f) .setPosition(getVisualPosition()); - bell.setChanged(); updateRotation(partialTick); - - super.init(partialTick); + updateLight(partialTick); } private OrientedInstance createBellInstance() { @@ -81,8 +76,8 @@ public class BellVisual extends AbstractBlockEntityVisual imple } @Override - public void updateLight() { - relight(pos, bell); + public void updateLight(float partialTick) { + relight(bell); } @Override diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java index 42c31200e..32c77be61 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/ChestVisual.java @@ -51,22 +51,20 @@ public class ChestVisual extends Abstrac return new SingleMeshModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "lock"), Materials.CHEST); }); - private OrientedInstance bottom; - private TransformedInstance lid; - private TransformedInstance lock; + private final OrientedInstance bottom; + private final TransformedInstance lid; + private final TransformedInstance lock; + + private final ChestType chestType; + private final Float2FloatFunction lidProgress; - private ChestType chestType; private final Quaternionf baseRotation = new Quaternionf(); - private Float2FloatFunction lidProgress; private float lastProgress = Float.NaN; - public ChestVisual(VisualizationContext ctx, T blockEntity) { - super(ctx, blockEntity); - } + public ChestVisual(VisualizationContext ctx, T blockEntity, float partialTick) { + super(ctx, blockEntity, partialTick); - @Override - public void init(float partialTick) { chestType = blockState.hasProperty(ChestBlock.TYPE) ? blockState.getValue(ChestBlock.TYPE) : ChestType.SINGLE; Material texture = Sheets.chooseMaterial(blockEntity, chestType, isChristmas()); @@ -90,8 +88,7 @@ public class ChestVisual extends Abstrac bottom.setChanged(); applyLidTransform(lidProgress.get(partialTick)); - - super.init(partialTick); + updateLight(partialTick); } private OrientedInstance createBottomInstance(Material texture) { @@ -153,8 +150,8 @@ public class ChestVisual extends Abstrac } @Override - public void updateLight() { - relight(pos, bottom, lid, lock); + public void updateLight(float partialTick) { + relight(bottom, lid, lock); } @Override diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java index a4c27ee82..b0a72f0a7 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/MinecartVisual.java @@ -38,19 +38,32 @@ public class MinecartVisual extends SimpleEntityVisu public static final ModelHolder SPAWNER_BODY_MODEL = createBodyModelHolder(ModelLayers.SPAWNER_MINECART); public static final ModelHolder TNT_BODY_MODEL = createBodyModelHolder(ModelLayers.TNT_MINECART); - private final ModelHolder bodyModel; - - private TransformedInstance body; + private final TransformedInstance body; @Nullable private TransformedInstance contents; - private BlockState blockState; - private boolean active; + + private final ModelHolder bodyModel; private final PoseStack stack = new PoseStack(); - public MinecartVisual(VisualizationContext ctx, T entity, ModelHolder bodyModel) { - super(ctx, entity); + private BlockState blockState; + private boolean active; + + public MinecartVisual(VisualizationContext ctx, T entity, float partialTick, ModelHolder bodyModel) { + super(ctx, entity, partialTick); + 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) { @@ -59,22 +72,6 @@ public class MinecartVisual 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() { return instancerProvider.instancer(InstanceTypes.TRANSFORMED, bodyModel.get()) .createInstance(); @@ -110,8 +107,6 @@ public class MinecartVisual extends SimpleEntityVisu } contents = createContentsInstance(); } - - updateLight(); } @Override @@ -198,6 +193,9 @@ public class MinecartVisual extends SimpleEntityVisu stack.scale(-1.0F, -1.0F, 1.0F); body.setTransform(stack) .setChanged(); + + // TODO: Use LitVisual if possible. + updateLight(partialTick); } protected void updateContents(TransformedInstance contents, PoseStack stack, float partialTick) { @@ -205,8 +203,8 @@ public class MinecartVisual extends SimpleEntityVisu .setChanged(); } - public void updateLight() { - relight(entity.blockPosition(), body, contents); + public void updateLight(float partialTick) { + relight(partialTick, body, contents); } @Override diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/ShulkerBoxVisual.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/ShulkerBoxVisual.java index 45b76ba87..5b648c532 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/ShulkerBoxVisual.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/ShulkerBoxVisual.java @@ -34,19 +34,16 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual extends MinecartVisual { private static final int WHITE_OVERLAY = OverlayTexture.pack(OverlayTexture.u(1.0F), 10); - public TntMinecartVisual(VisualizationContext ctx, T entity) { - super(ctx, entity, TNT_BODY_MODEL); + public TntMinecartVisual(VisualizationContext ctx, T entity, float partialTick) { + super(ctx, entity, partialTick, TNT_BODY_MODEL); } @Override diff --git a/common/src/main/java/dev/engine_room/flywheel/vanilla/VanillaVisuals.java b/common/src/main/java/dev/engine_room/flywheel/vanilla/VanillaVisuals.java index f39a0a186..fb7bc7a10 100644 --- a/common/src/main/java/dev/engine_room/flywheel/vanilla/VanillaVisuals.java +++ b/common/src/main/java/dev/engine_room/flywheel/vanilla/VanillaVisuals.java @@ -47,27 +47,27 @@ public class VanillaVisuals { .apply(); 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) .apply(); 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) .apply(); 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) .apply(); 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) .apply(); 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) .apply(); 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) .apply(); builder(EntityType.TNT_MINECART) diff --git a/common/src/test/java/dev/engine_room/flywheel/lib/util/TestAtomicBitset.java b/common/src/test/java/dev/engine_room/flywheel/lib/util/TestAtomicBitset.java index dd93838ac..a81d719cd 100644 --- a/common/src/test/java/dev/engine_room/flywheel/lib/util/TestAtomicBitset.java +++ b/common/src/test/java/dev/engine_room/flywheel/lib/util/TestAtomicBitset.java @@ -7,9 +7,9 @@ public class TestAtomicBitset { @Test void testNextClearBit() { - var segmentLength = 1 << 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 segmentLength = 1 << 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); Assertions.assertEquals(0, bs.nextClearBit(0)); Assertions.assertEquals(1, bs.nextClearBit(1)); diff --git a/gradle.properties b/gradle.properties index 431fbe0d6..284ee34aa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,7 +19,8 @@ forge_version_range = [47.0.0,) # General build dependency versions 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 parchment_version = 2023.09.03 diff --git a/settings.gradle.kts b/settings.gradle.kts index cf8fd7a12..d9d1bb952 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -12,10 +12,11 @@ pluginManagement { maven("https://maven.parchmentmc.org") } - plugins { - val arch_loom_version: String by settings - id("dev.architectury.loom") version arch_loom_version - } + // FIXME: This doesn't do anything. The actual version is always the one defined in buildSrc/build.gradle.kts. +// plugins { +// val arch_loom_version: String by settings +// id("dev.architectury.loom") version arch_loom_version +// } } rootProject.name = "Flywheel"