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.LevelRenderer;
import net.minecraft.client.renderer.RenderBuffers; import net.minecraft.client.renderer.RenderBuffers;
public record RenderContext(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack, public interface RenderContext {
Matrix4f projection, Matrix4f viewProjection, Camera camera, float partialTick) { LevelRenderer renderer();
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());
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 { public interface DynamicVisual extends Visual {
/** /**
* Called every frame. * Called every frame.
* <p> * <br>
* <b>DISPATCHED IN PARALLEL</b>. Ensure proper synchronization if you need to mutate anything outside this visual. * The implementation is free to parallelize calls to this method.
* <p> * 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. * {@link Instancer}/{@link Instance} creation/acquisition is safe here.
*/ */
void beginFrame(VisualFrameContext ctx); 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. * Called when a section this visual is contained in receives a light update.
* <br> * <br>
* Even if multiple sections are updated at the same time, this method will only be called once. * 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(); void updateLight();

View file

@ -22,9 +22,12 @@ import com.jozufozu.flywheel.api.instance.Instancer;
public interface TickableVisual extends Visual { public interface TickableVisual extends Visual {
/** /**
* Called every tick. * Called every tick.
* <p> * <br>
* <b>DISPATCHED IN PARALLEL</b>. Ensure proper synchronization if you need to mutate anything outside this visual. * The implementation is free to parallelize calls to this method.
* <p> * 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. * {@link Instancer}/{@link Instance} creation/acquisition is safe here.
*/ */
void tick(VisualTickContext ctx); void tick(VisualTickContext ctx);

View file

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

View file

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

View file

@ -1,4 +1,11 @@
package com.jozufozu.flywheel.api.visual; 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. * 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.SortedSet;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.joml.FrustumIntersection; import org.joml.FrustumIntersection;
import org.joml.Matrix4f; 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.config.FlwConfig;
import com.jozufozu.flywheel.extension.LevelExtension; import com.jozufozu.flywheel.extension.LevelExtension;
import com.jozufozu.flywheel.impl.task.FlwTaskExecutor; 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.BlockEntityStorage;
import com.jozufozu.flywheel.impl.visualization.manager.EffectStorage; import com.jozufozu.flywheel.impl.visualization.manager.EffectStorage;
import com.jozufozu.flywheel.impl.visualization.manager.EntityStorage; 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. * 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 static final LevelAttached<VisualizationManagerImpl> MANAGERS = new LevelAttached<>(VisualizationManagerImpl::new, VisualizationManagerImpl::delete);
private final Engine engine; private final Engine engine;
@ -67,7 +70,7 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
private final VisualManagerImpl<Entity, EntityStorage> entities; private final VisualManagerImpl<Entity, EntityStorage> entities;
private final VisualManagerImpl<Effect, EffectStorage> effects; private final VisualManagerImpl<Effect, EffectStorage> effects;
private final Plan<TickContext> tickPlan; private final Plan<VisualTickContext> tickPlan;
private final Plan<RenderContext> framePlan; private final Plan<RenderContext> framePlan;
private final Flag tickFlag = new NamedFlag("tick"); private final Flag tickFlag = new NamedFlag("tick");
@ -85,18 +88,20 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
.createEngine(level); .createEngine(level);
taskExecutor = FlwTaskExecutor.get(); taskExecutor = FlwTaskExecutor.get();
blockEntities = new VisualManagerImpl<>(new BlockEntityStorage(this)); Supplier<VisualizationContext> contextSupplier = () -> new VisualizationContextImpl(engine, engine.renderOrigin());
entities = new VisualManagerImpl<>(new EntityStorage(this));
effects = new VisualManagerImpl<>(new EffectStorage(this));
var blockEntitiesStorage = blockEntities.getStorage(); var blockEntitiesStorage = new BlockEntityStorage(contextSupplier);
var entitiesStorage = entities.getStorage(); var entitiesStorage = new EntityStorage(contextSupplier);
var effectsStorage = effects.getStorage(); var effectsStorage = new EffectStorage(contextSupplier);
tickPlan = MapContextPlan.map(this::createVisualTickContext)
.to(NestedPlan.of(SimplePlan.<VisualTickContext>of(context -> blockEntities.processQueue(0)) 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(blockEntitiesStorage.getTickPlan()), SimplePlan.<VisualTickContext>of(context -> entities.processQueue(0))
.then(entitiesStorage.getTickPlan()), SimplePlan.<VisualTickContext>of(context -> effects.processQueue(0)) .then(entitiesStorage.getTickPlan()), SimplePlan.<VisualTickContext>of(context -> effects.processQueue(0))
.then(effectsStorage.getTickPlan()))) .then(effectsStorage.getTickPlan()))
.then(RaisePlan.raise(tickFlag)) .then(RaisePlan.raise(tickFlag))
.simplify(); .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)); viewProjection.translate((float) (renderOrigin.getX() - cameraX), (float) (renderOrigin.getY() - cameraY), (float) (renderOrigin.getZ() - cameraZ));
FrustumIntersection frustum = new FrustumIntersection(viewProjection); FrustumIntersection frustum = new FrustumIntersection(viewProjection);
return new VisualFrameContext(cameraX, cameraY, cameraZ, frustum, ctx.partialTick(), frameLimiter); return new VisualFrameContextImpl(cameraX, cameraY, cameraZ, frustum, ctx.partialTick(), frameLimiter);
}
private VisualTickContext createVisualTickContext(TickContext ctx) {
return new VisualTickContext(ctx.cameraX(), ctx.cameraY(), ctx.cameraZ(), frameLimiter);
} }
protected DistanceUpdateLimiterImpl createUpdateLimiter() { protected DistanceUpdateLimiterImpl createUpdateLimiter() {
@ -151,6 +152,7 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
} }
} }
@Contract("null -> false")
public static boolean supportsVisualization(@Nullable LevelAccessor level) { public static boolean supportsVisualization(@Nullable LevelAccessor level) {
if (!BackendManager.isOn()) { if (!BackendManager.isOn()) {
return false; return false;
@ -198,11 +200,6 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
MANAGERS.reset(); MANAGERS.reset();
} }
@Override
public VisualizationContext get() {
return new VisualizationContext(engine, engine.renderOrigin());
}
@Override @Override
public Vec3i getRenderOrigin() { public Vec3i getRenderOrigin() {
return engine.renderOrigin(); return engine.renderOrigin();
@ -239,7 +236,7 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier<
tickLimiter.tick(); 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 java.util.SortedSet;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final; 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.BeginFrameEvent;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent; 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.RenderStage;
import com.jozufozu.flywheel.api.event.RenderStageEvent; import com.jozufozu.flywheel.api.event.RenderStageEvent;
import com.jozufozu.flywheel.impl.event.RenderContextImpl;
import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl; import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
@ -45,12 +46,13 @@ abstract class LevelRendererMixin {
private Long2ObjectMap<SortedSet<BlockDestructionProgress>> destructionProgress; private Long2ObjectMap<SortedSet<BlockDestructionProgress>> destructionProgress;
@Unique @Unique
private RenderContext flywheel$renderContext; @Nullable
private RenderContextImpl flywheel$renderContext;
// @Inject(method = "renderLevel", at = @At("HEAD")) // @Inject(method = "renderLevel", at = @At("HEAD"))
@Inject(method = "renderLevel", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I")) @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) { 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)); 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")) @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) { private void flywheel$beforeRenderCrumbling(CallbackInfo ci) {
if (flywheel$renderContext == null) {
return;
}
var manager = VisualizationManagerImpl.get(level); var manager = VisualizationManagerImpl.get(level);
if (manager != null) { if (manager != null) {
manager.renderCrumbling(flywheel$renderContext, destructionProgress); manager.renderCrumbling(flywheel$renderContext, destructionProgress);