Merge branch 'refs/heads/1.20/dev' into feat/multi-loader-1.20.4

# Conflicts:
#	gradle.properties
This commit is contained in:
IThundxr 2024-07-03 09:47:31 -04:00
commit a9c4e5c6f4
Failed to generate hash of commit
38 changed files with 469 additions and 443 deletions

View file

@ -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")
}

View file

@ -1,8 +1,5 @@
package dev.engine_room.flywheel.api.vertex;
import org.joml.Vector3f;
import org.joml.Vector4f;
/**
* A read only view of a vertex buffer.
*
@ -40,14 +37,6 @@ public interface VertexList {
float normalZ(int index);
default Vector4f getPos(int i, Vector4f dest) {
return dest.set(x(i), y(i), z(i));
}
default Vector3f getNormal(int i, Vector3f dest) {
return dest.set(normalX(i), normalY(i), normalZ(i));
}
default void write(MutableVertexList dst, int srcIndex, int dstIndex) {
dst.x(dstIndex, x(srcIndex));
dst.y(dstIndex, y(srcIndex));

View file

@ -1,5 +1,7 @@
package dev.engine_room.flywheel.api.visual;
import java.util.List;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
/**
@ -14,5 +16,5 @@ public interface Effect {
* @param ctx The visualization context.
* @return An arbitrary EffectVisual.
*/
EffectVisual<?> visualize(VisualizationContext ctx);
List<EffectVisual<?>> visualize(VisualizationContext ctx, float partialTick);
}

View file

@ -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.
*
* <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
* 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>
* @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.
*
* <p>This method is only called once, upon visual creation,
* after {@link #init} and before {@link #collectLightSections}.</p>
* <p>Even if multiple sections are updated at the same time, this method will only be called once.</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

View file

@ -8,13 +8,6 @@ package dev.engine_room.flywheel.api.visual;
* @see LitVisual
*/
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.
*

View file

@ -1,5 +1,7 @@
package dev.engine_room.flywheel.api.visualization;
import java.util.List;
import dev.engine_room.flywheel.api.visual.BlockEntityVisual;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -16,7 +18,7 @@ public interface BlockEntityVisualizer<T extends BlockEntity> {
* @param blockEntity The block entity to construct a visual for.
* @return The visual.
*/
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}.

View file

@ -1,5 +1,7 @@
package dev.engine_room.flywheel.api.visualization;
import java.util.List;
import dev.engine_room.flywheel.api.visual.EntityVisual;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.world.entity.Entity;
@ -16,7 +18,7 @@ public interface EntityVisualizer<T extends Entity> {
* @param entity The entity to construct a visual for.
* @return The visual.
*/
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}.

View file

@ -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<I extends Instance> implements Instancer<I> {
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<InstanceHandleImpl> 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<I> type, Environment environment) {
this.type = type;

View file

@ -3,7 +3,7 @@ package dev.engine_room.flywheel.backend.engine.uniform;
import org.joml.Matrix4f;
import org.lwjgl.system.MemoryUtil;
import dev.engine_room.flywheel.lib.math.MatrixMath;
import dev.engine_room.flywheel.lib.util.ExtraMemoryOps;
import net.minecraft.core.BlockPos;
import net.minecraft.tags.FluidTags;
import net.minecraft.world.level.Level;
@ -46,7 +46,7 @@ class UniformWriter {
}
static long writeMat4(long ptr, Matrix4f mat) {
MatrixMath.writeUnsafe(ptr, mat);
ExtraMemoryOps.putMatrix4f(ptr, mat);
return ptr + 64;
}

View file

@ -2,7 +2,6 @@ package dev.engine_room.flywheel.lib.instance;
import dev.engine_room.flywheel.api.instance.InstanceHandle;
import dev.engine_room.flywheel.api.instance.InstanceType;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.texture.OverlayTexture;
public abstract class ColoredLitInstance extends AbstractInstance implements FlatLit {
@ -11,43 +10,42 @@ public abstract class ColoredLitInstance extends AbstractInstance implements Fla
public byte b = (byte) 0xFF;
public byte a = (byte) 0xFF;
public int packedLight;
public int overlay = OverlayTexture.NO_OVERLAY;
public int light = 0;
public ColoredLitInstance(InstanceType<? extends ColoredLitInstance> type, InstanceHandle handle) {
super(type, handle);
}
public ColoredLitInstance setColor(int color) {
return setColor(color, false);
public ColoredLitInstance color(int color) {
return color(color, false);
}
public ColoredLitInstance setColor(int color, boolean alpha) {
public ColoredLitInstance color(int color, boolean alpha) {
byte r = (byte) ((color >> 16) & 0xFF);
byte g = (byte) ((color >> 8) & 0xFF);
byte b = (byte) (color & 0xFF);
if (alpha) {
byte a = (byte) ((color >> 24) & 0xFF);
return setColor(r, g, b, a);
return color(r, g, b, a);
} else {
return setColor(r, g, b);
return color(r, g, b);
}
}
public ColoredLitInstance setColor(int r, int g, int b) {
return setColor((byte) r, (byte) g, (byte) b);
public ColoredLitInstance color(int r, int g, int b) {
return color((byte) r, (byte) g, (byte) b);
}
public ColoredLitInstance setColor(byte r, byte g, byte b) {
public ColoredLitInstance color(byte r, byte g, byte b) {
this.r = r;
this.g = g;
this.b = b;
return this;
}
public ColoredLitInstance setColor(byte r, byte g, byte b, byte a) {
public ColoredLitInstance color(byte r, byte g, byte b, byte a) {
this.r = r;
this.g = g;
this.b = b;
@ -55,19 +53,14 @@ public abstract class ColoredLitInstance extends AbstractInstance implements Fla
return this;
}
@Override
public ColoredLitInstance light(int blockLight, int skyLight) {
return light(LightTexture.pack(blockLight, skyLight));
}
@Override
public ColoredLitInstance light(int packedLight) {
this.packedLight = packedLight;
return this;
}
public ColoredLitInstance setOverlay(int overlay) {
public ColoredLitInstance overlay(int overlay) {
this.overlay = overlay;
return this;
}
@Override
public ColoredLitInstance light(int light) {
this.light = light;
return this;
}
}

View file

@ -1,26 +1,64 @@
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 {
/**
* Set the block and sky light values for this instance.
* @param blockLight Block light value
* @param skyLight Sky light value
* @return {@code this} for chaining
*/
FlatLit light(int blockLight, int skyLight);
/**
* Set the packed light value for this instance.
* @param packedLight Packed block and sky light per {@link LightTexture#pack(int, int)}
* @return {@code this} for chaining
*/
FlatLit light(int packedLight);
/**
* Set the block and sky light values for this instance.
* @param blockLight Block light value
* @param skyLight Sky light value
* @return {@code this} for chaining
*/
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());
}
}

View file

@ -8,7 +8,7 @@ import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.api.layout.FloatRepr;
import dev.engine_room.flywheel.api.layout.IntegerRepr;
import dev.engine_room.flywheel.api.layout.LayoutBuilder;
import dev.engine_room.flywheel.lib.math.MatrixMath;
import dev.engine_room.flywheel.lib.util.ExtraMemoryOps;
public final class InstanceTypes {
public static final InstanceType<TransformedInstance> TRANSFORMED = SimpleInstanceType.builder(TransformedInstance::new)
@ -24,12 +24,10 @@ public final class InstanceTypes {
MemoryUtil.memPutByte(ptr + 1, instance.g);
MemoryUtil.memPutByte(ptr + 2, instance.b);
MemoryUtil.memPutByte(ptr + 3, instance.a);
MemoryUtil.memPutShort(ptr + 4, (short) (instance.overlay & 0xFFFF));
MemoryUtil.memPutShort(ptr + 6, (short) (instance.overlay >> 16 & 0xFFFF));
MemoryUtil.memPutShort(ptr + 8, (short) (instance.packedLight & 0xFFFF));
MemoryUtil.memPutShort(ptr + 10, (short) (instance.packedLight >> 16 & 0xFFFF));
MatrixMath.writeUnsafe(ptr + 12, instance.model);
MatrixMath.writeUnsafe(ptr + 76, instance.normal);
ExtraMemoryOps.put2x16(ptr + 4, instance.overlay);
ExtraMemoryOps.put2x16(ptr + 8, instance.light);
ExtraMemoryOps.putMatrix4f(ptr + 12, instance.model);
ExtraMemoryOps.putMatrix3f(ptr + 76, instance.normal);
})
.vertexShader(Flywheel.rl("instance/transformed.vert"))
.cullShader(Flywheel.rl("instance/cull/transformed.glsl"))
@ -49,20 +47,15 @@ public final class InstanceTypes {
MemoryUtil.memPutByte(ptr + 1, instance.g);
MemoryUtil.memPutByte(ptr + 2, instance.b);
MemoryUtil.memPutByte(ptr + 3, instance.a);
MemoryUtil.memPutShort(ptr + 4, (short) (instance.overlay & 0xFFFF));
MemoryUtil.memPutShort(ptr + 6, (short) (instance.overlay >> 16 & 0xFFFF));
MemoryUtil.memPutShort(ptr + 8, (short) (instance.packedLight & 0xFFFF));
MemoryUtil.memPutShort(ptr + 10, (short) (instance.packedLight >> 16 & 0xFFFF));
ExtraMemoryOps.put2x16(ptr + 4, instance.overlay);
ExtraMemoryOps.put2x16(ptr + 8, instance.light);
MemoryUtil.memPutFloat(ptr + 12, instance.posX);
MemoryUtil.memPutFloat(ptr + 16, instance.posY);
MemoryUtil.memPutFloat(ptr + 20, instance.posZ);
MemoryUtil.memPutFloat(ptr + 24, instance.pivotX);
MemoryUtil.memPutFloat(ptr + 28, instance.pivotY);
MemoryUtil.memPutFloat(ptr + 32, instance.pivotZ);
MemoryUtil.memPutFloat(ptr + 36, instance.rotation.x);
MemoryUtil.memPutFloat(ptr + 40, instance.rotation.y);
MemoryUtil.memPutFloat(ptr + 44, instance.rotation.z);
MemoryUtil.memPutFloat(ptr + 48, instance.rotation.w);
ExtraMemoryOps.putQuaternionf(ptr + 36, instance.rotation);
})
.vertexShader(Flywheel.rl("instance/oriented.vert"))
.cullShader(Flywheel.rl("instance/cull/oriented.glsl"))

View file

@ -7,25 +7,10 @@ import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.lwjgl.system.MemoryUtil;
import com.mojang.blaze3d.vertex.PoseStack;
public final class MatrixMath {
private MatrixMath() {
}
public static PoseStack copyPoseStack(PoseStack stack) {
PoseStack copy = new PoseStack();
copy.last()
.pose()
.set(stack.last()
.pose());
copy.last()
.normal()
.set(stack.last()
.normal());
return copy;
}
public static float transformPositionX(Matrix4f matrix, float x, float y, float z) {
return fma(matrix.m00(), x, fma(matrix.m10(), y, fma(matrix.m20(), z, matrix.m30())));
}
@ -50,37 +35,6 @@ public final class MatrixMath {
return fma(matrix.m02(), x, fma(matrix.m12(), y, matrix.m22() * z));
}
public static void writeUnsafe(long ptr, Matrix4f matrix) {
MemoryUtil.memPutFloat(ptr, matrix.m00());
MemoryUtil.memPutFloat(ptr + 4, matrix.m01());
MemoryUtil.memPutFloat(ptr + 8, matrix.m02());
MemoryUtil.memPutFloat(ptr + 12, matrix.m03());
MemoryUtil.memPutFloat(ptr + 16, matrix.m10());
MemoryUtil.memPutFloat(ptr + 20, matrix.m11());
MemoryUtil.memPutFloat(ptr + 24, matrix.m12());
MemoryUtil.memPutFloat(ptr + 28, matrix.m13());
MemoryUtil.memPutFloat(ptr + 32, matrix.m20());
MemoryUtil.memPutFloat(ptr + 36, matrix.m21());
MemoryUtil.memPutFloat(ptr + 40, matrix.m22());
MemoryUtil.memPutFloat(ptr + 44, matrix.m23());
MemoryUtil.memPutFloat(ptr + 48, matrix.m30());
MemoryUtil.memPutFloat(ptr + 52, matrix.m31());
MemoryUtil.memPutFloat(ptr + 56, matrix.m32());
MemoryUtil.memPutFloat(ptr + 60, matrix.m33());
}
public static void writeUnsafe(long ptr, Matrix3f matrix) {
MemoryUtil.memPutFloat(ptr, matrix.m00());
MemoryUtil.memPutFloat(ptr + 4, matrix.m01());
MemoryUtil.memPutFloat(ptr + 8, matrix.m02());
MemoryUtil.memPutFloat(ptr + 12, matrix.m10());
MemoryUtil.memPutFloat(ptr + 16, matrix.m11());
MemoryUtil.memPutFloat(ptr + 20, matrix.m12());
MemoryUtil.memPutFloat(ptr + 24, matrix.m20());
MemoryUtil.memPutFloat(ptr + 28, matrix.m21());
MemoryUtil.memPutFloat(ptr + 32, matrix.m22());
}
/**
* Extracts the greatest scale factor across all axes from the given matrix.
*

View file

@ -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<AtomicBitsetSegments> segments;
private final AtomicReference<AtomicBitSetSegments> 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);

View file

@ -0,0 +1,82 @@
package dev.engine_room.flywheel.lib.util;
import org.joml.Matrix3fc;
import org.joml.Matrix4fc;
import org.joml.Quaternionfc;
import org.joml.Vector2fc;
import org.joml.Vector3fc;
import org.joml.Vector4fc;
import org.lwjgl.system.MemoryUtil;
public final class ExtraMemoryOps {
private ExtraMemoryOps() {
}
public static void put4x8(long ptr, int value) {
MemoryUtil.memPutByte(ptr, (byte) (value & 0xFF));
MemoryUtil.memPutByte(ptr + 1, (byte) (value >>> 8 & 0xFF));
MemoryUtil.memPutByte(ptr + 2, (byte) (value >>> 16 & 0xFF));
MemoryUtil.memPutByte(ptr + 3, (byte) (value >>> 24 & 0xFF));
}
public static void put2x16(long ptr, int value) {
MemoryUtil.memPutShort(ptr, (short) (value & 0xFFFF));
MemoryUtil.memPutShort(ptr + 2, (short) (value >>> 16 & 0xFFFF));
}
public static void putVector2f(long ptr, Vector2fc vector) {
MemoryUtil.memPutFloat(ptr, vector.x());
MemoryUtil.memPutFloat(ptr + 4, vector.y());
}
public static void putVector3f(long ptr, Vector3fc vector) {
MemoryUtil.memPutFloat(ptr, vector.x());
MemoryUtil.memPutFloat(ptr + 4, vector.y());
MemoryUtil.memPutFloat(ptr + 8, vector.z());
}
public static void putVector4f(long ptr, Vector4fc vector) {
MemoryUtil.memPutFloat(ptr, vector.x());
MemoryUtil.memPutFloat(ptr + 4, vector.y());
MemoryUtil.memPutFloat(ptr + 8, vector.z());
MemoryUtil.memPutFloat(ptr + 12, vector.w());
}
public static void putQuaternionf(long ptr, Quaternionfc quaternion) {
MemoryUtil.memPutFloat(ptr, quaternion.x());
MemoryUtil.memPutFloat(ptr + 4, quaternion.y());
MemoryUtil.memPutFloat(ptr + 8, quaternion.z());
MemoryUtil.memPutFloat(ptr + 12, quaternion.w());
}
public static void putMatrix3f(long ptr, Matrix3fc matrix) {
MemoryUtil.memPutFloat(ptr, matrix.m00());
MemoryUtil.memPutFloat(ptr + 4, matrix.m01());
MemoryUtil.memPutFloat(ptr + 8, matrix.m02());
MemoryUtil.memPutFloat(ptr + 12, matrix.m10());
MemoryUtil.memPutFloat(ptr + 16, matrix.m11());
MemoryUtil.memPutFloat(ptr + 20, matrix.m12());
MemoryUtil.memPutFloat(ptr + 24, matrix.m20());
MemoryUtil.memPutFloat(ptr + 28, matrix.m21());
MemoryUtil.memPutFloat(ptr + 32, matrix.m22());
}
public static void putMatrix4f(long ptr, Matrix4fc matrix) {
MemoryUtil.memPutFloat(ptr, matrix.m00());
MemoryUtil.memPutFloat(ptr + 4, matrix.m01());
MemoryUtil.memPutFloat(ptr + 8, matrix.m02());
MemoryUtil.memPutFloat(ptr + 12, matrix.m03());
MemoryUtil.memPutFloat(ptr + 16, matrix.m10());
MemoryUtil.memPutFloat(ptr + 20, matrix.m11());
MemoryUtil.memPutFloat(ptr + 24, matrix.m12());
MemoryUtil.memPutFloat(ptr + 28, matrix.m13());
MemoryUtil.memPutFloat(ptr + 32, matrix.m20());
MemoryUtil.memPutFloat(ptr + 36, matrix.m21());
MemoryUtil.memPutFloat(ptr + 40, matrix.m22());
MemoryUtil.memPutFloat(ptr + 44, matrix.m23());
MemoryUtil.memPutFloat(ptr + 48, matrix.m30());
MemoryUtil.memPutFloat(ptr + 52, matrix.m31());
MemoryUtil.memPutFloat(ptr + 56, matrix.m32());
MemoryUtil.memPutFloat(ptr + 60, matrix.m33());
}
}

View file

@ -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<T extends BlockEntity> 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<T extends BlockEntity> 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<T extends BlockEntity> 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<T extends BlockEntity> 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);
}
}

View file

@ -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<T extends Entity> 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 <em>level</em> position.
*
@ -84,4 +84,12 @@ public abstract class AbstractEntityVisual<T extends Entity> 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);
}
}

View file

@ -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<? 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();
}
}
}

View file

@ -1,5 +1,6 @@
package dev.engine_room.flywheel.lib.visual;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
@ -23,8 +24,8 @@ public class SimpleBlockEntityVisualizer<T extends BlockEntity> implements Block
}
@Override
public BlockEntityVisual<? super T> createVisual(VisualizationContext ctx, T blockEntity) {
return visualFactory.create(ctx, blockEntity);
public List<BlockEntityVisual<? super T>> createVisual(VisualizationContext ctx, T blockEntity, float partialTick) {
return List.of(visualFactory.create(ctx, blockEntity, partialTick));
}
@Override
@ -45,7 +46,7 @@ public class SimpleBlockEntityVisualizer<T extends BlockEntity> implements Block
@FunctionalInterface
public interface Factory<T extends BlockEntity> {
BlockEntityVisual<? super T> create(VisualizationContext ctx, T blockEntity);
BlockEntityVisual<? super T> create(VisualizationContext ctx, T blockEntity, float partialTick);
}
/**

View file

@ -9,8 +9,8 @@ import net.minecraft.world.entity.Entity;
public class SimpleEntityVisual<T extends Entity> extends AbstractEntityVisual<T> implements SimpleDynamicVisual {
protected final List<EntityComponent> 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) {

View file

@ -1,5 +1,6 @@
package dev.engine_room.flywheel.lib.visual;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
@ -23,8 +24,8 @@ public class SimpleEntityVisualizer<T extends Entity> implements EntityVisualize
}
@Override
public EntityVisual<? super T> createVisual(VisualizationContext ctx, T entity) {
return visualFactory.create(ctx, entity);
public List<EntityVisual<? super T>> createVisual(VisualizationContext ctx, T entity, float partialTick) {
return List.of(visualFactory.create(ctx, entity, partialTick));
}
@Override
@ -45,7 +46,7 @@ public class SimpleEntityVisualizer<T extends Entity> implements EntityVisualize
@FunctionalInterface
public interface Factory<T extends Entity> {
EntityVisual<? super T> create(VisualizationContext ctx, T entity);
EntityVisual<? super T> create(VisualizationContext ctx, T entity, float partialTick);
}
/**

View file

@ -109,7 +109,7 @@ public class HitboxComponent implements EntityComponent {
.loadIdentity()
.translate(entityX - bbWidthHalf, entityY + entity.getEyeHeight() - 0.01, entityZ - bbWidthHalf)
.scale(bbWidth, 0.02f, bbWidth)
.setColor(255, 0, 0)
.color(255, 0, 0)
.setChanged();
}
@ -119,7 +119,7 @@ public class HitboxComponent implements EntityComponent {
.loadIdentity()
.translate(entityX, entityY + entity.getEyeHeight(), entityZ)
.rotate(new Quaternionf().rotateTo(0, 1, 0, (float) viewVector.x, (float) viewVector.y, (float) viewVector.z))
.setColor(0, 0, 255)
.color(0, 0, 255)
.setChanged();
}

View file

@ -17,6 +17,7 @@ import dev.engine_room.flywheel.api.event.RenderStage;
import dev.engine_room.flywheel.api.instance.Instance;
import dev.engine_room.flywheel.api.task.Plan;
import dev.engine_room.flywheel.api.task.TaskExecutor;
import dev.engine_room.flywheel.api.visual.BlockEntityVisual;
import dev.engine_room.flywheel.api.visual.DynamicVisual;
import dev.engine_room.flywheel.api.visual.Effect;
import dev.engine_room.flywheel.api.visual.TickableVisual;
@ -261,21 +262,23 @@ public class VisualizationManagerImpl implements VisualizationManager {
continue;
}
var visual = blockEntities.getStorage()
var visualList = blockEntities.getStorage()
.visualAtPos(entry.getLongKey());
if (visual == null) {
if (visualList == null || visualList.isEmpty()) {
// The block doesn't have a visual, this is probably the common case.
continue;
}
List<Instance> instances = new ArrayList<>();
visual.collectCrumblingInstances(instance -> {
if (instance != null) {
instances.add(instance);
}
});
for (BlockEntityVisual<?> visual : visualList) {
visual.collectCrumblingInstances(instance -> {
if (instance != null) {
instances.add(instance);
}
});
}
if (instances.isEmpty()) {
// The visual doesn't want to render anything crumbling.

View file

@ -1,11 +1,11 @@
package dev.engine_room.flywheel.impl.visualization.manager;
import java.util.List;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import dev.engine_room.flywheel.api.visual.BlockEntityVisual;
import dev.engine_room.flywheel.api.visual.Visual;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.impl.visualization.storage.Storage;
import dev.engine_room.flywheel.lib.visual.VisualizationHelper;
@ -17,14 +17,14 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
public class BlockEntityStorage extends Storage<BlockEntity> {
private final Long2ObjectMap<BlockEntityVisual<?>> posLookup = new Long2ObjectOpenHashMap<>();
private final Long2ObjectMap<List<? extends BlockEntityVisual<?>>> posLookup = new Long2ObjectOpenHashMap<>();
public BlockEntityStorage(Supplier<VisualizationContext> visualizationContextSupplier) {
super(visualizationContextSupplier);
}
@Nullable
public BlockEntityVisual<?> visualAtPos(long pos) {
public List<? extends BlockEntityVisual<?>> visualAtPos(long pos) {
return posLookup.get(pos);
}
@ -53,19 +53,18 @@ public class BlockEntityStorage extends Storage<BlockEntity> {
}
@Override
@Nullable
protected Visual createRaw(BlockEntity obj) {
protected List<? extends BlockEntityVisual<?>> createRaw(BlockEntity obj, float partialTick) {
var visualizer = VisualizationHelper.getVisualizer(obj);
if (visualizer == null) {
return null;
return List.of();
}
var visual = visualizer.createVisual(visualizationContextSupplier.get(), obj);
var visualList = visualizer.createVisual(visualizationContextSupplier.get(), obj, partialTick);
BlockPos blockPos = obj.getBlockPos();
posLookup.put(blockPos.asLong(), visual);
posLookup.put(blockPos.asLong(), visualList);
return visual;
return visualList;
}
@Override

View file

@ -1,5 +1,6 @@
package dev.engine_room.flywheel.impl.visualization.manager;
import java.util.List;
import java.util.function.Supplier;
import dev.engine_room.flywheel.api.visual.Effect;
@ -13,8 +14,8 @@ public class EffectStorage extends Storage<Effect> {
}
@Override
protected EffectVisual<?> createRaw(Effect obj) {
return obj.visualize(visualizationContextSupplier.get());
protected List<? extends EffectVisual<?>> createRaw(Effect obj, float partialTick) {
return obj.visualize(visualizationContextSupplier.get(), partialTick);
}
@Override

View file

@ -1,10 +1,9 @@
package dev.engine_room.flywheel.impl.visualization.manager;
import java.util.List;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import dev.engine_room.flywheel.api.visual.Visual;
import dev.engine_room.flywheel.api.visual.EntityVisual;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.impl.visualization.storage.Storage;
import dev.engine_room.flywheel.lib.visual.VisualizationHelper;
@ -17,14 +16,13 @@ public class EntityStorage extends Storage<Entity> {
}
@Override
@Nullable
protected Visual createRaw(Entity obj) {
protected List<? extends EntityVisual<?>> createRaw(Entity obj, float partialTick) {
var visualizer = VisualizationHelper.getVisualizer(obj);
if (visualizer == null) {
return null;
return List.of();
}
return visualizer.createVisual(visualizationContextSupplier.get(), obj);
return visualizer.createVisual(visualizationContextSupplier.get(), obj, partialTick);
}
@Override

View file

@ -26,7 +26,7 @@ public class VisualManagerImpl<T, S extends Storage<T>> implements VisualManager
@Override
public int getVisualCount() {
return getStorage().getAllVisuals().size();
return getStorage().visualCount();
}
@Override

View file

@ -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 {

View file

@ -1,13 +1,10 @@
package dev.engine_room.flywheel.impl.visualization.storage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import dev.engine_room.flywheel.api.task.Plan;
import dev.engine_room.flywheel.api.visual.DynamicVisual;
import dev.engine_room.flywheel.api.visual.LitVisual;
@ -29,31 +26,137 @@ public abstract class Storage<T> {
protected final List<SimpleTickableVisual> simpleTickableVisuals = new ArrayList<>();
protected final LitVisualStorage litVisuals = new LitVisualStorage();
private final Map<T, Visual> visuals = new Reference2ObjectOpenHashMap<>();
private final Map<T, List<? extends Visual>> visuals = new Reference2ObjectOpenHashMap<>();
public Storage(Supplier<VisualizationContext> visualizationContextSupplier) {
this.visualizationContextSupplier = visualizationContextSupplier;
}
public Collection<Visual> getAllVisuals() {
return visuals.values();
public int visualCount() {
int out = 0;
for (var visualList : visuals.values()) {
out += visualList.size();
}
return out;
}
public void add(T obj, float partialTick) {
Visual visual = visuals.get(obj);
var visualList = this.visuals.get(obj);
if (visual == null) {
if (visualList == null) {
create(obj, partialTick);
}
}
public void remove(T obj) {
Visual visual = visuals.remove(obj);
var visualList = this.visuals.remove(obj);
if (visual == null) {
if (visualList == null || visualList.isEmpty()) {
return;
}
for (Visual visual : visualList) {
remove(visual);
}
}
public void update(T obj, float partialTick) {
var visualList = visuals.get(obj);
if (visualList == null || visualList.isEmpty()) {
return;
}
for (Visual visual : visualList) {
visual.update(partialTick);
}
}
public void recreateAll(float partialTick) {
tickableVisuals.clear();
dynamicVisuals.clear();
simpleTickableVisuals.clear();
simpleDynamicVisuals.clear();
litVisuals.clear();
visuals.replaceAll((obj, visuals) -> {
visuals.forEach(Visual::delete);
var out = createRaw(obj, partialTick);
if (out.isEmpty()) {
return null;
}
for (Visual visual : out) {
setup(visual);
}
return out;
});
}
public void invalidate() {
tickableVisuals.clear();
dynamicVisuals.clear();
litVisuals.clear();
for (var visualList : visuals.values()) {
for (Visual visual : visualList) {
visual.delete();
}
}
visuals.clear();
}
private void create(T obj, float partialTick) {
var visuals = createRaw(obj, partialTick);
if (visuals.isEmpty()) {
return;
}
this.visuals.put(obj, visuals);
for (Visual visual : visuals) {
setup(visual);
}
}
protected abstract List<? extends Visual> createRaw(T obj, float partialTick);
public Plan<DynamicVisual.Context> framePlan() {
return NestedPlan.of(dynamicVisuals, litVisuals.plan(), ForEachPlan.of(() -> simpleDynamicVisuals, SimpleDynamicVisual::beginFrame));
}
public Plan<TickableVisual.Context> tickPlan() {
return NestedPlan.of(tickableVisuals, ForEachPlan.of(() -> simpleTickableVisuals, SimpleTickableVisual::tick));
}
public void enqueueLightUpdateSection(long section) {
litVisuals.enqueueLightUpdateSection(section);
}
private void setup(Visual visual) {
if (visual instanceof TickableVisual tickable) {
if (visual instanceof SimpleTickableVisual simpleTickable) {
simpleTickableVisuals.add(simpleTickable);
} else {
tickableVisuals.add(tickable, tickable.planTick());
}
}
if (visual instanceof DynamicVisual dynamic) {
if (visual instanceof SimpleDynamicVisual simpleDynamic) {
simpleDynamicVisuals.add(simpleDynamic);
} else {
dynamicVisuals.add(dynamic, dynamic.planFrame());
}
}
if (visual instanceof LitVisual lit) {
litVisuals.setNotifierAndAdd(lit);
}
}
private void remove(Visual visual) {
if (visual instanceof TickableVisual tickable) {
if (visual instanceof SimpleTickableVisual simpleTickable) {
simpleTickableVisuals.remove(simpleTickable);
@ -74,92 +177,6 @@ public abstract class Storage<T> {
visual.delete();
}
public void update(T obj, float partialTick) {
Visual visual = visuals.get(obj);
if (visual == null) {
return;
}
visual.update(partialTick);
}
public void recreateAll(float partialTick) {
tickableVisuals.clear();
dynamicVisuals.clear();
simpleTickableVisuals.clear();
simpleDynamicVisuals.clear();
litVisuals.clear();
visuals.replaceAll((obj, visual) -> {
visual.delete();
Visual out = createRaw(obj);
if (out != null) {
setup(out, partialTick);
}
return out;
});
}
public void invalidate() {
tickableVisuals.clear();
dynamicVisuals.clear();
litVisuals.clear();
visuals.values()
.forEach(Visual::delete);
visuals.clear();
}
private void create(T obj, float partialTick) {
Visual visual = createRaw(obj);
if (visual != null) {
setup(visual, partialTick);
visuals.put(obj, visual);
}
}
@Nullable
protected abstract Visual createRaw(T obj);
public Plan<DynamicVisual.Context> framePlan() {
return NestedPlan.of(dynamicVisuals, litVisuals.plan(), ForEachPlan.of(() -> simpleDynamicVisuals, SimpleDynamicVisual::beginFrame));
}
public Plan<TickableVisual.Context> tickPlan() {
return NestedPlan.of(tickableVisuals, ForEachPlan.of(() -> simpleTickableVisuals, SimpleTickableVisual::tick));
}
public void enqueueLightUpdateSection(long section) {
litVisuals.enqueueLightUpdateSection(section);
}
private void setup(Visual visual, float partialTick) {
visual.init(partialTick);
if (visual instanceof TickableVisual tickable) {
if (visual instanceof SimpleTickableVisual simpleTickable) {
simpleTickableVisuals.add(simpleTickable);
} else {
tickableVisuals.add(tickable, tickable.planTick());
}
}
if (visual instanceof DynamicVisual dynamic) {
if (visual instanceof SimpleDynamicVisual simpleDynamic) {
simpleDynamicVisuals.add(simpleDynamic);
} else {
dynamicVisuals.add(dynamic, dynamic.planFrame());
}
}
if (visual instanceof LitVisual lit) {
litVisuals.addAndInitNotifier(lit);
}
}
/**
* Is the given object currently capable of being added?
*

View file

@ -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);
});
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<BellBlockEntity> imple
}
@Override
public void updateLight() {
relight(pos, bell);
public void updateLight(float partialTick) {
relight(bell);
}
@Override

View file

@ -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);
});
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<T extends BlockEntity & LidBlockEntity> 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<T extends BlockEntity & LidBlockEntity> extends Abstrac
}
@Override
public void updateLight() {
relight(pos, bottom, lid, lock);
public void updateLight(float partialTick) {
relight(bottom, lid, lock);
}
@Override

View file

@ -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 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<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() {
return instancerProvider.instancer(InstanceTypes.TRANSFORMED, bodyModel.get())
.createInstance();
@ -110,8 +107,6 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
}
contents = createContentsInstance();
}
updateLight();
}
@Override
@ -198,6 +193,9 @@ public class MinecartVisual<T extends AbstractMinecart> 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<T extends AbstractMinecart> extends SimpleEntityVisu
.setChanged();
}
public void updateLight() {
relight(entity.blockPosition(), body, contents);
public void updateLight(float partialTick) {
relight(partialTick, body, contents);
}
@Override

View file

@ -34,19 +34,16 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "lid"), Materials.SHULKER);
});
private TransformedInstance base;
private TransformedInstance lid;
private final TransformedInstance base;
private final TransformedInstance lid;
private final PoseStack stack = new PoseStack();
private float lastProgress = Float.NaN;
public ShulkerBoxVisual(VisualizationContext ctx, ShulkerBoxBlockEntity blockEntity) {
super(ctx, blockEntity);
}
public ShulkerBoxVisual(VisualizationContext ctx, ShulkerBoxBlockEntity blockEntity, float partialTick) {
super(ctx, blockEntity, partialTick);
@Override
public void init(float partialTick) {
DyeColor color = blockEntity.getColor();
Material texture;
if (color == null) {
@ -67,12 +64,11 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
.translateY(-1);
base = createBaseInstance(texture).setTransform(stack);
lid = createLidInstance(texture).setTransform(stack);
base.setChanged();
lid = createLidInstance(texture).setTransform(stack);
lid.setChanged();
super.init(partialTick);
updateLight(partialTick);
}
private TransformedInstance createBaseInstance(Material texture) {
@ -119,8 +115,8 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
}
@Override
public void updateLight() {
relight(pos, base, lid);
public void updateLight(float partialTick) {
relight(base, lid);
}
@Override

View file

@ -11,8 +11,8 @@ import net.minecraft.world.entity.vehicle.MinecartTNT;
public class TntMinecartVisual<T extends MinecartTNT> extends MinecartVisual<T> {
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
@ -35,7 +35,7 @@ public class TntMinecartVisual<T extends MinecartTNT> extends MinecartVisual<T>
}
contents.setTransform(stack)
.setOverlay(overlay)
.overlay(overlay)
.setChanged();
}
}

View file

@ -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)

View file

@ -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));

View file

@ -19,7 +19,8 @@ neoforge_version_range = [20.4.234,)
# 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
parchment_version = 2024.04.14
# Minecraft build dependency versions

View file

@ -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"