Don't take this out of context

- Make all context records in the API interfaces.
- Move records to impl package.
- Update *Visual docs.
- Inline TickContext.
This commit is contained in:
Jozufozu 2024-01-22 15:49:15 -08:00
parent 06359c6ea2
commit 3f8876b073
15 changed files with 152 additions and 51 deletions

View file

@ -9,13 +9,20 @@ import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.RenderBuffers;
public record RenderContext(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack,
Matrix4f projection, Matrix4f viewProjection, Camera camera, float partialTick) {
public static RenderContext create(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack, Matrix4f projection, Camera camera, float partialTick) {
Matrix4f viewProjection = new Matrix4f(projection);
viewProjection.mul(stack.last()
.pose());
public interface RenderContext {
LevelRenderer renderer();
return new RenderContext(renderer, level, buffers, stack, projection, viewProjection, camera, partialTick);
}
ClientLevel level();
RenderBuffers buffers();
PoseStack stack();
Matrix4f projection();
Matrix4f viewProjection();
Camera camera();
float partialTick();
}

View file

@ -15,9 +15,12 @@ import com.jozufozu.flywheel.api.instance.Instancer;
public interface DynamicVisual extends Visual {
/**
* Called every frame.
* <p>
* <b>DISPATCHED IN PARALLEL</b>. Ensure proper synchronization if you need to mutate anything outside this visual.
* <p>
* <br>
* The implementation is free to parallelize calls to this method.
* You must ensure proper synchronization if you need to mutate anything outside this visual.
* <br>
* This method and {@link TickableVisual#tick} will never be called simultaneously.
* <br>
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
*/
void beginFrame(VisualFrameContext ctx);

View file

@ -15,6 +15,11 @@ public interface LitVisual extends Visual {
* Called when a section this visual is contained in receives a light update.
* <br>
* Even if multiple sections are updated at the same time, this method will only be called once.
* <br>
* The implementation is free to parallelize calls to this method, as well as call into
* {@link DynamicVisual#beginFrame} 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 by {@link DynamicVisual#beginFrame}.
*/
void updateLight();

View file

@ -22,9 +22,12 @@ import com.jozufozu.flywheel.api.instance.Instancer;
public interface TickableVisual extends Visual {
/**
* Called every tick.
* <p>
* <b>DISPATCHED IN PARALLEL</b>. Ensure proper synchronization if you need to mutate anything outside this visual.
* <p>
* <br>
* The implementation is free to parallelize calls to this method.
* You must ensure proper synchronization if you need to mutate anything outside this visual.
* <br>
* This method and {@link DynamicVisual#beginFrame} will never be called simultaneously.
* <br>
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
*/
void tick(VisualTickContext ctx);

View file

@ -5,6 +5,8 @@ package com.jozufozu.flywheel.api.visual;
*
* @see DynamicVisual
* @see TickableVisual
* @see PlannedVisual
* @see LitVisual
*/
public interface Visual {
/**

View file

@ -2,6 +2,16 @@ package com.jozufozu.flywheel.api.visual;
import org.joml.FrustumIntersection;
public record VisualFrameContext(double cameraX, double cameraY, double cameraZ, FrustumIntersection frustum,
float partialTick, DistanceUpdateLimiter limiter) {
public interface VisualFrameContext {
double cameraX();
double cameraY();
double cameraZ();
FrustumIntersection frustum();
float partialTick();
DistanceUpdateLimiter limiter();
}

View file

@ -1,4 +1,11 @@
package com.jozufozu.flywheel.api.visual;
public record VisualTickContext(double cameraX, double cameraY, double cameraZ, DistanceUpdateLimiter limiter) {
public interface VisualTickContext {
double cameraX();
double cameraY();
double cameraZ();
DistanceUpdateLimiter limiter();
}

View file

@ -6,10 +6,17 @@ import net.minecraft.core.Vec3i;
/**
* A context object passed on visual creation.
*
* @param instancerProvider The {@link InstancerProvider} that the visual can use to get instancers to render models.
* @param renderOrigin The origin of the renderer as a world position.
* All models render as if this position is (0, 0, 0).
*/
public record VisualizationContext(InstancerProvider instancerProvider, Vec3i renderOrigin) {
public interface VisualizationContext {
/**
* @return The {@link InstancerProvider} that the visual can use to get instancers to render models.
*/
InstancerProvider instancerProvider();
/**
* All models render as if this position is (0, 0, 0).
*
* @return The origin of the renderer as a world position.
*/
Vec3i renderOrigin();
}

View file

@ -0,0 +1,23 @@
package com.jozufozu.flywheel.impl.event;
import org.joml.Matrix4f;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Camera;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.RenderBuffers;
public record RenderContextImpl(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack,
Matrix4f projection, Matrix4f viewProjection, Camera camera,
float partialTick) implements RenderContext {
public static RenderContextImpl create(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack, Matrix4f projection, Camera camera, float partialTick) {
Matrix4f viewProjection = new Matrix4f(projection);
viewProjection.mul(stack.last()
.pose());
return new RenderContextImpl(renderer, level, buffers, stack, projection, viewProjection, camera, partialTick);
}
}

View file

@ -0,0 +1,10 @@
package com.jozufozu.flywheel.impl.visual;
import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.visual.DistanceUpdateLimiter;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
public record VisualFrameContextImpl(double cameraX, double cameraY, double cameraZ, FrustumIntersection frustum,
float partialTick, DistanceUpdateLimiter limiter) implements VisualFrameContext {
}

View file

@ -0,0 +1,8 @@
package com.jozufozu.flywheel.impl.visual;
import com.jozufozu.flywheel.api.visual.DistanceUpdateLimiter;
import com.jozufozu.flywheel.api.visual.VisualTickContext;
public record VisualTickContextImpl(double cameraX, double cameraY, double cameraZ,
DistanceUpdateLimiter limiter) implements VisualTickContext {
}

View file

@ -1,4 +0,0 @@
package com.jozufozu.flywheel.impl.visualization;
public record TickContext(double cameraX, double cameraY, double cameraZ) {
}

View file

@ -0,0 +1,17 @@
package com.jozufozu.flywheel.impl.visualization;
import com.jozufozu.flywheel.api.instance.InstancerProvider;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
import net.minecraft.core.Vec3i;
/**
* A context object passed on visual creation.
*
* @param instancerProvider The {@link InstancerProvider} that the visual can use to get instancers to render models.
* @param renderOrigin The origin of the renderer as a world position.
* All models render as if this position is (0, 0, 0).
*/
public record VisualizationContextImpl(InstancerProvider instancerProvider,
Vec3i renderOrigin) implements VisualizationContext {
}

View file

@ -5,6 +5,7 @@ import java.util.List;
import java.util.SortedSet;
import java.util.function.Supplier;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import org.joml.FrustumIntersection;
import org.joml.Matrix4f;
@ -28,6 +29,8 @@ import com.jozufozu.flywheel.api.visualization.VisualizationManager;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.extension.LevelExtension;
import com.jozufozu.flywheel.impl.task.FlwTaskExecutor;
import com.jozufozu.flywheel.impl.visual.VisualFrameContextImpl;
import com.jozufozu.flywheel.impl.visual.VisualTickContextImpl;
import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityStorage;
import com.jozufozu.flywheel.impl.visualization.manager.EffectStorage;
import com.jozufozu.flywheel.impl.visualization.manager.EntityStorage;
@ -57,7 +60,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
/**
* A manager class for a single world where visualization is supported.
*/
public class VisualizationManagerImpl implements VisualizationManager, Supplier<VisualizationContext> {
public class VisualizationManagerImpl implements VisualizationManager {
private static final LevelAttached<VisualizationManagerImpl> MANAGERS = new LevelAttached<>(VisualizationManagerImpl::new, VisualizationManagerImpl::delete);
private final Engine engine;
@ -67,7 +70,7 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
private final VisualManagerImpl<Entity, EntityStorage> entities;
private final VisualManagerImpl<Effect, EffectStorage> effects;
private final Plan<TickContext> tickPlan;
private final Plan<VisualTickContext> tickPlan;
private final Plan<RenderContext> framePlan;
private final Flag tickFlag = new NamedFlag("tick");
@ -85,18 +88,20 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
.createEngine(level);
taskExecutor = FlwTaskExecutor.get();
blockEntities = new VisualManagerImpl<>(new BlockEntityStorage(this));
entities = new VisualManagerImpl<>(new EntityStorage(this));
effects = new VisualManagerImpl<>(new EffectStorage(this));
Supplier<VisualizationContext> contextSupplier = () -> new VisualizationContextImpl(engine, engine.renderOrigin());
var blockEntitiesStorage = blockEntities.getStorage();
var entitiesStorage = entities.getStorage();
var effectsStorage = effects.getStorage();
tickPlan = MapContextPlan.map(this::createVisualTickContext)
.to(NestedPlan.of(SimplePlan.<VisualTickContext>of(context -> blockEntities.processQueue(0))
var blockEntitiesStorage = new BlockEntityStorage(contextSupplier);
var entitiesStorage = new EntityStorage(contextSupplier);
var effectsStorage = new EffectStorage(contextSupplier);
blockEntities = new VisualManagerImpl<>(blockEntitiesStorage);
entities = new VisualManagerImpl<>(entitiesStorage);
effects = new VisualManagerImpl<>(effectsStorage);
tickPlan = NestedPlan.of(SimplePlan.<VisualTickContext>of(context -> blockEntities.processQueue(0))
.then(blockEntitiesStorage.getTickPlan()), SimplePlan.<VisualTickContext>of(context -> entities.processQueue(0))
.then(entitiesStorage.getTickPlan()), SimplePlan.<VisualTickContext>of(context -> effects.processQueue(0))
.then(effectsStorage.getTickPlan())))
.then(effectsStorage.getTickPlan()))
.then(RaisePlan.raise(tickFlag))
.simplify();
@ -135,11 +140,7 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
viewProjection.translate((float) (renderOrigin.getX() - cameraX), (float) (renderOrigin.getY() - cameraY), (float) (renderOrigin.getZ() - cameraZ));
FrustumIntersection frustum = new FrustumIntersection(viewProjection);
return new VisualFrameContext(cameraX, cameraY, cameraZ, frustum, ctx.partialTick(), frameLimiter);
}
private VisualTickContext createVisualTickContext(TickContext ctx) {
return new VisualTickContext(ctx.cameraX(), ctx.cameraY(), ctx.cameraZ(), frameLimiter);
return new VisualFrameContextImpl(cameraX, cameraY, cameraZ, frustum, ctx.partialTick(), frameLimiter);
}
protected DistanceUpdateLimiterImpl createUpdateLimiter() {
@ -151,6 +152,7 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
}
}
@Contract("null -> false")
public static boolean supportsVisualization(@Nullable LevelAccessor level) {
if (!BackendManager.isOn()) {
return false;
@ -198,11 +200,6 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
MANAGERS.reset();
}
@Override
public VisualizationContext get() {
return new VisualizationContext(engine, engine.renderOrigin());
}
@Override
public Vec3i getRenderOrigin() {
return engine.renderOrigin();
@ -239,7 +236,7 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
tickLimiter.tick();
tickPlan.execute(taskExecutor, new TickContext(cameraX, cameraY, cameraZ));
tickPlan.execute(taskExecutor, new VisualTickContextImpl(cameraX, cameraY, cameraZ, frameLimiter));
}
/**

View file

@ -2,6 +2,7 @@ package com.jozufozu.flywheel.mixin;
import java.util.SortedSet;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
@ -15,9 +16,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.api.event.BeginFrameEvent;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.event.RenderStageEvent;
import com.jozufozu.flywheel.impl.event.RenderContextImpl;
import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl;
import com.mojang.blaze3d.vertex.PoseStack;
@ -45,12 +46,13 @@ abstract class LevelRendererMixin {
private Long2ObjectMap<SortedSet<BlockDestructionProgress>> destructionProgress;
@Unique
private RenderContext flywheel$renderContext;
@Nullable
private RenderContextImpl flywheel$renderContext;
// @Inject(method = "renderLevel", at = @At("HEAD"))
@Inject(method = "renderLevel", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"))
private void flywheel$beginRender(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) {
flywheel$renderContext = RenderContext.create((LevelRenderer) (Object) this, level, renderBuffers, poseStack, projectionMatrix, camera, partialTick);
flywheel$renderContext = RenderContextImpl.create((LevelRenderer) (Object) this, level, renderBuffers, poseStack, projectionMatrix, camera, partialTick);
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(flywheel$renderContext));
}
@ -67,6 +69,10 @@ abstract class LevelRendererMixin {
@Inject(method = "renderLevel", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V", args = "ldc=destroyProgress"))
private void flywheel$beforeRenderCrumbling(CallbackInfo ci) {
if (flywheel$renderContext == null) {
return;
}
var manager = VisualizationManagerImpl.get(level);
if (manager != null) {
manager.renderCrumbling(flywheel$renderContext, destructionProgress);