From 3f8876b073ab90830c57c34c68bd8d5fc8d8d1a4 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Mon, 22 Jan 2024 15:49:15 -0800 Subject: [PATCH] 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. --- .../flywheel/api/event/RenderContext.java | 23 +++++++---- .../flywheel/api/visual/DynamicVisual.java | 9 ++-- .../flywheel/api/visual/LitVisual.java | 5 +++ .../flywheel/api/visual/TickableVisual.java | 9 ++-- .../jozufozu/flywheel/api/visual/Visual.java | 2 + .../api/visual/VisualFrameContext.java | 14 ++++++- .../api/visual/VisualTickContext.java | 9 +++- .../visualization/VisualizationContext.java | 17 +++++--- .../impl/event/RenderContextImpl.java | 23 +++++++++++ .../impl/visual/VisualFrameContextImpl.java | 10 +++++ .../impl/visual/VisualTickContextImpl.java | 8 ++++ .../impl/visualization/TickContext.java | 4 -- .../VisualizationContextImpl.java | 17 ++++++++ .../VisualizationManagerImpl.java | 41 +++++++++---------- .../flywheel/mixin/LevelRendererMixin.java | 12 ++++-- 15 files changed, 152 insertions(+), 51 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/impl/event/RenderContextImpl.java create mode 100644 src/main/java/com/jozufozu/flywheel/impl/visual/VisualFrameContextImpl.java create mode 100644 src/main/java/com/jozufozu/flywheel/impl/visual/VisualTickContextImpl.java delete mode 100644 src/main/java/com/jozufozu/flywheel/impl/visualization/TickContext.java create mode 100644 src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationContextImpl.java diff --git a/src/main/java/com/jozufozu/flywheel/api/event/RenderContext.java b/src/main/java/com/jozufozu/flywheel/api/event/RenderContext.java index a336d97be..4108b9934 100644 --- a/src/main/java/com/jozufozu/flywheel/api/event/RenderContext.java +++ b/src/main/java/com/jozufozu/flywheel/api/event/RenderContext.java @@ -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(); } diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/DynamicVisual.java b/src/main/java/com/jozufozu/flywheel/api/visual/DynamicVisual.java index 28a85ec0a..426fa419c 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/DynamicVisual.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/DynamicVisual.java @@ -15,9 +15,12 @@ import com.jozufozu.flywheel.api.instance.Instancer; public interface DynamicVisual extends Visual { /** * Called every frame. - *

- * DISPATCHED IN PARALLEL. Ensure proper synchronization if you need to mutate anything outside this visual. - *

+ *
+ * The implementation is free to parallelize calls to this method. + * You must ensure proper synchronization if you need to mutate anything outside this visual. + *
+ * This method and {@link TickableVisual#tick} will never be called simultaneously. + *
* {@link Instancer}/{@link Instance} creation/acquisition is safe here. */ void beginFrame(VisualFrameContext ctx); diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/LitVisual.java b/src/main/java/com/jozufozu/flywheel/api/visual/LitVisual.java index a60eb753e..697f324d0 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/LitVisual.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/LitVisual.java @@ -15,6 +15,11 @@ public interface LitVisual extends Visual { * Called when a section this visual is contained in receives a light update. *
* Even if multiple sections are updated at the same time, this method will only be called once. + *
+ * 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(); diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/TickableVisual.java b/src/main/java/com/jozufozu/flywheel/api/visual/TickableVisual.java index 822d34f84..1d4f3056b 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/TickableVisual.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/TickableVisual.java @@ -22,9 +22,12 @@ import com.jozufozu.flywheel.api.instance.Instancer; public interface TickableVisual extends Visual { /** * Called every tick. - *

- * DISPATCHED IN PARALLEL. Ensure proper synchronization if you need to mutate anything outside this visual. - *

+ *
+ * The implementation is free to parallelize calls to this method. + * You must ensure proper synchronization if you need to mutate anything outside this visual. + *
+ * This method and {@link DynamicVisual#beginFrame} will never be called simultaneously. + *
* {@link Instancer}/{@link Instance} creation/acquisition is safe here. */ void tick(VisualTickContext ctx); diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/Visual.java b/src/main/java/com/jozufozu/flywheel/api/visual/Visual.java index 87c392315..5421d4397 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/Visual.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/Visual.java @@ -5,6 +5,8 @@ package com.jozufozu.flywheel.api.visual; * * @see DynamicVisual * @see TickableVisual + * @see PlannedVisual + * @see LitVisual */ public interface Visual { /** diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/VisualFrameContext.java b/src/main/java/com/jozufozu/flywheel/api/visual/VisualFrameContext.java index dc0011b3b..2fe30d1ad 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/VisualFrameContext.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/VisualFrameContext.java @@ -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(); } diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/VisualTickContext.java b/src/main/java/com/jozufozu/flywheel/api/visual/VisualTickContext.java index 6185d2dd9..7faa1ff29 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/VisualTickContext.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/VisualTickContext.java @@ -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(); } diff --git a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationContext.java b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationContext.java index cc2c30d53..f8c116359 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationContext.java +++ b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationContext.java @@ -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(); } diff --git a/src/main/java/com/jozufozu/flywheel/impl/event/RenderContextImpl.java b/src/main/java/com/jozufozu/flywheel/impl/event/RenderContextImpl.java new file mode 100644 index 000000000..d5d5d1636 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/event/RenderContextImpl.java @@ -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); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/visual/VisualFrameContextImpl.java b/src/main/java/com/jozufozu/flywheel/impl/visual/VisualFrameContextImpl.java new file mode 100644 index 000000000..2fa833c12 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/visual/VisualFrameContextImpl.java @@ -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 { +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/visual/VisualTickContextImpl.java b/src/main/java/com/jozufozu/flywheel/impl/visual/VisualTickContextImpl.java new file mode 100644 index 000000000..176d58543 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/visual/VisualTickContextImpl.java @@ -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 { +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/TickContext.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/TickContext.java deleted file mode 100644 index 4d005e58e..000000000 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/TickContext.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.jozufozu.flywheel.impl.visualization; - -public record TickContext(double cameraX, double cameraY, double cameraZ) { -} diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationContextImpl.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationContextImpl.java new file mode 100644 index 000000000..eaf888a82 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationContextImpl.java @@ -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 { +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java index 7417641da..432ee9670 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java @@ -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 { +public class VisualizationManagerImpl implements VisualizationManager { private static final LevelAttached MANAGERS = new LevelAttached<>(VisualizationManagerImpl::new, VisualizationManagerImpl::delete); private final Engine engine; @@ -67,7 +70,7 @@ public class VisualizationManagerImpl implements VisualizationManager, Supplier< private final VisualManagerImpl entities; private final VisualManagerImpl effects; - private final Plan tickPlan; + private final Plan tickPlan; private final Plan 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 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.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.of(context -> blockEntities.processQueue(0)) .then(blockEntitiesStorage.getTickPlan()), SimplePlan.of(context -> entities.processQueue(0)) .then(entitiesStorage.getTickPlan()), SimplePlan.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)); } /** diff --git a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java index 367d224db..7f3196d8f 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java @@ -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> 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);