Merge remote-tracking branch 'upstream/1.20/dev' into feat/multi-loader-1.21

# Conflicts:
#	forge/src/main/java/dev/engine_room/flywheel/impl/FlwCommands.java
This commit is contained in:
IThundxr 2024-11-12 20:00:34 -05:00
commit c95bd4c722
Failed to generate hash of commit
7 changed files with 352 additions and 101 deletions

View file

@ -11,7 +11,7 @@ import net.minecraft.core.SectionPos;
// Massive kudos to RogueLogix for figuring out this LUT scheme.
// First layer is Y, then X, then Z.
public final class LightLut {
private final Layer<Layer<IntLayer>> indices = new Layer<>();
public final Layer<Layer<IntLayer>> indices = new Layer<>();
public void add(long position, int index) {
final var x = SectionPos.x(position);
@ -49,7 +49,7 @@ public final class LightLut {
return out;
}
private static final class Layer<T> {
public static final class Layer<T> {
private boolean hasBase = false;
private int base = 0;
private Object[] nextLayer = new Object[0];
@ -79,23 +79,34 @@ public final class LightLut {
}
}
public int base() {
return base;
}
public int size() {
return nextLayer.length;
}
@Nullable
public T getRaw(int i) {
if (i < 0) {
return null;
}
if (i >= nextLayer.length) {
return null;
}
return (T) nextLayer[i];
}
@Nullable
public T get(int i) {
if (!hasBase) {
return null;
}
if (i < base) {
return null;
}
final var offset = i - base;
if (offset >= nextLayer.length) {
return null;
}
return (T) nextLayer[offset];
return getRaw(i - base);
}
public T computeIfAbsent(int i, Supplier<T> ifAbsent) {
@ -142,7 +153,7 @@ public final class LightLut {
}
}
private static final class IntLayer {
public static final class IntLayer {
private boolean hasBase = false;
private int base = 0;
private int[] indices = new int[0];
@ -156,6 +167,34 @@ public final class LightLut {
}
}
public int base() {
return base;
}
public int size() {
return indices.length;
}
public int getRaw(int i) {
if (i < 0) {
return 0;
}
if (i >= indices.length) {
return 0;
}
return indices[i];
}
public int get(int i) {
if (!hasBase) {
return 0;
}
return getRaw(i - base);
}
public void set(int i, int index) {
if (!hasBase) {
base = i;

View file

@ -6,15 +6,25 @@ import org.jetbrains.annotations.Nullable;
import org.lwjgl.system.MemoryUtil;
import dev.engine_room.flywheel.api.task.Plan;
import dev.engine_room.flywheel.api.visual.Effect;
import dev.engine_room.flywheel.api.visual.EffectVisual;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
import dev.engine_room.flywheel.backend.engine.indirect.StagingBuffer;
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
import dev.engine_room.flywheel.lib.instance.InstanceTypes;
import dev.engine_room.flywheel.lib.instance.TransformedInstance;
import dev.engine_room.flywheel.lib.math.MoreMath;
import dev.engine_room.flywheel.lib.task.SimplePlan;
import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
import dev.engine_room.flywheel.lib.visual.component.HitboxComponent;
import dev.engine_room.flywheel.lib.visual.util.InstanceRecycler;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.Long2IntMap;
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.LevelAccessor;
@ -35,7 +45,9 @@ import net.minecraft.world.level.lighting.LayerLightEventListener;
*
* <p>Thus, each section occupies 5832 bytes.
*/
public class LightStorage {
public class LightStorage implements Effect {
public static boolean DEBUG = false;
public static final int BLOCKS_PER_SECTION = 18 * 18 * 18;
public static final int LIGHT_SIZE_BYTES = BLOCKS_PER_SECTION;
public static final int SOLID_SIZE_BYTES = MoreMath.ceilingDiv(BLOCKS_PER_SECTION, Integer.SIZE) * Integer.BYTES;
@ -50,6 +62,7 @@ public class LightStorage {
private final BitSet changed = new BitSet();
private boolean needsLutRebuild = false;
private boolean isDebugOn = false;
private final LongSet updatedSections = new LongOpenHashSet();
@Nullable
@ -63,6 +76,16 @@ public class LightStorage {
section2ArenaIndex.defaultReturnValue(INVALID_SECTION);
}
@Override
public LevelAccessor level() {
return level;
}
@Override
public EffectVisual<?> visualize(VisualizationContext ctx, float partialTick) {
return new DebugVisual(ctx, partialTick);
}
/**
* Set the set of requested sections.
* <p> When set, this will be processed in the next frame plan. It may not be set every frame.
@ -79,6 +102,22 @@ public class LightStorage {
public <C> Plan<C> createFramePlan() {
return SimplePlan.of(() -> {
if (DEBUG != isDebugOn) {
var visualizationManager = VisualizationManager.get(level);
// Really should be non-null, but just in case.
if (visualizationManager != null) {
if (DEBUG) {
visualizationManager.effects()
.queueAdd(this);
} else {
visualizationManager.effects()
.queueRemove(this);
}
}
isDebugOn = DEBUG;
}
if (updatedSections.isEmpty() && requestedSections == null) {
return;
}
@ -442,4 +481,130 @@ public class LightStorage {
this.sectionOffset = sectionOffset;
}
}
public class DebugVisual implements EffectVisual<LightStorage>, SimpleDynamicVisual {
private final InstanceRecycler<TransformedInstance> boxes;
public DebugVisual(VisualizationContext ctx, float partialTick) {
boxes = new InstanceRecycler<>(() -> ctx.instancerProvider()
.instancer(InstanceTypes.TRANSFORMED, HitboxComponent.BOX_MODEL)
.createInstance());
}
@Override
public void beginFrame(Context ctx) {
boxes.resetCount();
setupSectionBoxes();
setupLutRangeBoxes();
boxes.discardExtra();
}
private void setupSectionBoxes() {
section2ArenaIndex.keySet()
.forEach(l -> {
var x = SectionPos.x(l);
var y = SectionPos.y(l);
var z = SectionPos.z(l);
var instance = boxes.get();
instance.setIdentityTransform()
.scale(16)
.translate(x, y, z)
.color(255, 255, 0)
.light(LightTexture.FULL_BRIGHT)
.setChanged();
});
}
private void setupLutRangeBoxes() {
var first = lut.indices;
var base1 = first.base();
var size1 = first.size();
for (int y = 0; y < size1; y++) {
var second = first.getRaw(y);
if (second == null) {
continue;
}
var base2 = second.base();
var size2 = second.size();
for (int x = 0; x < size2; x++) {
var third = second.getRaw(x);
if (third == null) {
continue;
}
var base3 = third.base();
var size3 = third.size();
for (int z = 0; z < size3; z++) {
float x1 = base2 * 16;
float y1 = base1 * 16;
float z1 = base3 * 16;
float x2 = (base2 + x) * 16 + 7.5f;
float y2 = (base1 + y) * 16 + 7.5f;
float z2 = (base3 + z) * 16 + 7.5f;
boxes.get()
.setIdentityTransform()
.translate(x1, y2, z2)
.scale(size2 * 16, 1, 1)
.color(255, 0, 0)
.light(LightTexture.FULL_BRIGHT)
.setChanged();
boxes.get()
.setIdentityTransform()
.translate(x2, y1, z2)
.scale(1, size1 * 16, 1)
.color(0, 255, 0)
.light(LightTexture.FULL_BRIGHT)
.setChanged();
boxes.get()
.setIdentityTransform()
.translate(x2, y2, z1)
.scale(1, 1, size3 * 16)
.color(0, 0, 255)
.light(LightTexture.FULL_BRIGHT)
.setChanged();
if (third.getRaw(z) == 0) {
float x3 = (base2 + x) * 16 + 6f;
float y3 = (base1 + y) * 16 + 6f;
float z3 = (base3 + z) * 16 + 6f;
// Freely representable section that is not filled.
boxes.get()
.setIdentityTransform()
.translate(x3, y3, z3)
.scale(4)
.color(0, 255, 255)
.light(LightTexture.FULL_BRIGHT)
.setChanged();
}
}
}
}
}
@Override
public void update(float partialTick) {
}
@Override
public void delete() {
boxes.delete();
}
}
}

View file

@ -80,6 +80,7 @@ public final class LineModelBuilder {
public Model build() {
vertexView.vertexCount(vertexCount);
vertexView.nativeMemoryOwner(data);
var boundingSphere = ModelUtil.computeBoundingSphere(vertexView);
boundingSphere.w += 0.1f; // make the bounding sphere a little bigger to account for line width
@ -137,7 +138,7 @@ public final class LineModelBuilder {
@Override
public void write(MutableVertexList vertexList) {
vertexList.writeAll(vertexList);
this.vertexList.writeAll(vertexList);
}
@Override

View file

@ -25,7 +25,7 @@ public final class HitboxComponent implements EntityComponent {
// | / | /
// |/ |/
// 001------101
private static final Model BOX_MODEL = new LineModelBuilder(12)
public static final Model BOX_MODEL = new LineModelBuilder(12)
// Starting from 0, 0, 0
.line(0, 0, 0, 0, 0, 1)
.line(0, 0, 0, 0, 1, 0)
@ -44,7 +44,7 @@ public final class HitboxComponent implements EntityComponent {
.line(1, 1, 0, 0, 1, 0)
.build();
private static final Model LINE_MODEL = new LineModelBuilder(1)
public static final Model LINE_MODEL = new LineModelBuilder(1)
.line(0, 0, 0, 0, 2, 0)
.build();

View file

@ -53,6 +53,7 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
lid = instances.childOrThrow("lid");
initialPose = createInitialPose();
applyTransform(partialTick);
}
private Matrix4f createInitialPose() {
@ -80,7 +81,11 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
return;
}
float progress = blockEntity.getProgress(context.partialTick());
applyTransform(context.partialTick());
}
private void applyTransform(float partialTicks) {
float progress = blockEntity.getProgress(partialTicks);
if (progress == lastProgress) {
return;
}

View file

@ -10,6 +10,7 @@ import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.backend.BackendManager;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import dev.engine_room.flywheel.backend.compile.PipelineCompiler;
import dev.engine_room.flywheel.backend.engine.LightStorage;
import dev.engine_room.flywheel.backend.engine.uniform.DebugMode;
import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
@ -85,46 +86,6 @@ public final class FlwCommands {
return Command.SINGLE_SUCCESS;
})));
command.then(ClientCommandManager.literal("crumbling")
.then(ClientCommandManager.argument("pos", BlockPosArgument.blockPos())
.then(ClientCommandManager.argument("stage", IntegerArgumentType.integer(0, 9))
.executes(context -> {
Entity executor = context.getSource()
.getEntity();
if (executor == null) {
return 0;
}
BlockPos pos = getBlockPos(context, "pos");
int value = IntegerArgumentType.getInteger(context, "stage");
executor.level()
.destroyBlockProgress(executor.getId(), pos, value);
return Command.SINGLE_SUCCESS;
}))));
command.then(ClientCommandManager.literal("debug")
.then(ClientCommandManager.argument("mode", DebugModeArgument.INSTANCE)
.executes(context -> {
DebugMode mode = context.getArgument("mode", DebugMode.class);
FrameUniforms.debugMode(mode);
return Command.SINGLE_SUCCESS;
})));
command.then(ClientCommandManager.literal("frustum")
.then(ClientCommandManager.literal("capture")
.executes(context -> {
FrameUniforms.captureFrustum();
return Command.SINGLE_SUCCESS;
}))
.then(ClientCommandManager.literal("unpause")
.executes(context -> {
FrameUniforms.unpauseFrustum();
return Command.SINGLE_SUCCESS;
})));
command.then(ClientCommandManager.literal("lightSmoothness")
.then(ClientCommandManager.argument("mode", LightSmoothnessArgument.INSTANCE)
.executes(context -> {
@ -167,9 +128,69 @@ public final class FlwCommands {
return Command.SINGLE_SUCCESS;
})));
command.then(createDebugCommand());
dispatcher.register(command);
}
private static LiteralArgumentBuilder<FabricClientCommandSource> createDebugCommand() {
var debug = ClientCommandManager.literal("debug");
debug.then(ClientCommandManager.literal("crumbling")
.then(ClientCommandManager.argument("pos", BlockPosArgument.blockPos())
.then(ClientCommandManager.argument("stage", IntegerArgumentType.integer(0, 9))
.executes(context -> {
Entity executor = context.getSource()
.getEntity();
if (executor == null) {
return 0;
}
BlockPos pos = getBlockPos(context, "pos");
int value = IntegerArgumentType.getInteger(context, "stage");
executor.level()
.destroyBlockProgress(executor.getId(), pos, value);
return Command.SINGLE_SUCCESS;
}))));
debug.then(ClientCommandManager.literal("shader")
.then(ClientCommandManager.argument("mode", DebugModeArgument.INSTANCE)
.executes(context -> {
DebugMode mode = context.getArgument("mode", DebugMode.class);
FrameUniforms.debugMode(mode);
return Command.SINGLE_SUCCESS;
})));
debug.then(ClientCommandManager.literal("frustum")
.then(ClientCommandManager.literal("capture")
.executes(context -> {
FrameUniforms.captureFrustum();
return Command.SINGLE_SUCCESS;
}))
.then(ClientCommandManager.literal("unpause")
.executes(context -> {
FrameUniforms.unpauseFrustum();
return Command.SINGLE_SUCCESS;
})));
debug.then(ClientCommandManager.literal("lightSections")
.then(ClientCommandManager.literal("on")
.executes(context -> {
LightStorage.DEBUG = true;
return Command.SINGLE_SUCCESS;
}))
.then(ClientCommandManager.literal("off")
.executes(context -> {
LightStorage.DEBUG = false;
return Command.SINGLE_SUCCESS;
})));
return debug;
}
// Client version of BlockPosArgument.getBlockPos
private static BlockPos getBlockPos(CommandContext<FabricClientCommandSource> context, String name) {
return context.getArgument(name, Coordinates.class).getBlockPos(context.getSource().getPlayer().createCommandSourceStack());

View file

@ -8,6 +8,7 @@ import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.backend.BackendManager;
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
import dev.engine_room.flywheel.backend.compile.PipelineCompiler;
import dev.engine_room.flywheel.backend.engine.LightStorage;
import dev.engine_room.flywheel.backend.engine.uniform.DebugMode;
import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms;
import net.minecraft.client.Minecraft;
@ -83,47 +84,7 @@ public final class FlwCommands {
return Command.SINGLE_SUCCESS;
})));
command.then(Commands.literal("crumbling")
.then(Commands.argument("pos", BlockPosArgument.blockPos())
.then(Commands.argument("stage", IntegerArgumentType.integer(0, 9))
.executes(context -> {
Entity executor = context.getSource()
.getEntity();
if (executor == null) {
return 0;
}
BlockPos pos = BlockPosArgument.getBlockPos(context, "pos");
int value = IntegerArgumentType.getInteger(context, "stage");
executor.level()
.destroyBlockProgress(executor.getId(), pos, value);
return Command.SINGLE_SUCCESS;
}))));
command.then(Commands.literal("debug")
.then(Commands.argument("mode", DebugModeArgument.INSTANCE)
.executes(context -> {
DebugMode mode = context.getArgument("mode", DebugMode.class);
FrameUniforms.debugMode(mode);
return Command.SINGLE_SUCCESS;
})));
command.then(Commands.literal("frustum")
.then(Commands.literal("capture")
.executes(context -> {
FrameUniforms.captureFrustum();
return Command.SINGLE_SUCCESS;
}))
.then(Commands.literal("unpause")
.executes(context -> {
FrameUniforms.unpauseFrustum();
return Command.SINGLE_SUCCESS;
})));
var lightSmoothnessValue = NeoForgeFlwConfig.INSTANCE.client.backendConfig.lightSmoothness;
var lightSmoothnessValue = ForgeFlwConfig.INSTANCE.client.backendConfig.lightSmoothness;
command.then(Commands.literal("lightSmoothness")
.then(Commands.argument("mode", LightSmoothnessArgument.INSTANCE)
.executes(context -> {
@ -137,7 +98,7 @@ public final class FlwCommands {
return Command.SINGLE_SUCCESS;
})));
var useLightDirectionsValue = NeoForgeFlwConfig.INSTANCE.client.backendConfig.useLightDirections;
var useLightDirectionsValue = ForgeFlwConfig.INSTANCE.client.backendConfig.useLightDirections;
command.then(Commands.literal("useLightDirections")
.executes(context -> {
if (useLightDirectionsValue.get()) {
@ -160,9 +121,68 @@ public final class FlwCommands {
return Command.SINGLE_SUCCESS;
})));
command.then(createDebugCommand());
event.getDispatcher().register(command);
}
private static LiteralArgumentBuilder<CommandSourceStack> createDebugCommand() {
var debug = Commands.literal("debug");
debug.then(Commands.literal("crumbling")
.then(Commands.argument("pos", BlockPosArgument.blockPos())
.then(Commands.argument("stage", IntegerArgumentType.integer(0, 9))
.executes(context -> {
Entity executor = context.getSource()
.getEntity();
if (executor == null) {
return 0;
}
BlockPos pos = BlockPosArgument.getBlockPos(context, "pos");
int value = IntegerArgumentType.getInteger(context, "stage");
executor.level()
.destroyBlockProgress(executor.getId(), pos, value);
return Command.SINGLE_SUCCESS;
}))));
debug.then(Commands.literal("shader")
.then(Commands.argument("mode", DebugModeArgument.INSTANCE)
.executes(context -> {
DebugMode mode = context.getArgument("mode", DebugMode.class);
FrameUniforms.debugMode(mode);
return Command.SINGLE_SUCCESS;
})));
debug.then(Commands.literal("frustum")
.then(Commands.literal("capture")
.executes(context -> {
FrameUniforms.captureFrustum();
return Command.SINGLE_SUCCESS;
}))
.then(Commands.literal("unpause")
.executes(context -> {
FrameUniforms.unpauseFrustum();
return Command.SINGLE_SUCCESS;
})));
debug.then(Commands.literal("lightSections")
.then(Commands.literal("on")
.executes(context -> {
LightStorage.DEBUG = true;
return Command.SINGLE_SUCCESS;
}))
.then(Commands.literal("off")
.executes(context -> {
LightStorage.DEBUG = false;
return Command.SINGLE_SUCCESS;
})));
return debug;
}
private static void sendMessage(CommandSourceStack source, Component message) {
source.sendSuccess(() -> message, true);
}