From e0342c4b785ef84481cc1750d7ea90a3a6e66888 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Wed, 5 Jan 2022 11:44:52 -0800 Subject: [PATCH 1/2] Better state restore in InstancingEngine - Attempt to fix optifine issues - Replace with {@code} --- .../flywheel/api/instance/DynamicInstance.java | 2 +- .../flywheel/api/instance/TickableInstance.java | 2 +- .../flywheel/backend/gl/GlVertexArray.java | 13 ++++++++++--- .../flywheel/backend/gl/buffer/GlBufferType.java | 8 ++++++++ .../backend/gl/versioned/GlVersioned.java | 2 +- .../backend/instancing/AbstractInstance.java | 6 +++--- .../blockentity/BlockEntityInstance.java | 6 +++--- .../instancing/instancing/InstancingEngine.java | 10 +++++++--- .../flywheel/backend/source/SourceFile.java | 2 +- .../jozufozu/flywheel/core/materials/FlatLit.java | 4 ++-- .../jozufozu/flywheel/core/model/WorldModel.java | 2 +- .../flywheel/core/shader/spec/ProgramSpec.java | 4 ++-- .../flywheel/mixin/BufferUploaderAccessor.java | 15 +++++++++++++++ 13 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java b/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java index 14310c962..86e43e77b 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java @@ -30,7 +30,7 @@ public interface DynamicInstance extends Instance { *
You might want to opt out of this if you want your animations to remain smooth * even when far away from the camera. It is recommended to keep this as is, however. * - * @return true if your instance should be slow ticked. + * @return {@code true} if your instance should be slow ticked. */ default boolean decreaseFramerateWithDistance() { return true; diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/TickableInstance.java b/src/main/java/com/jozufozu/flywheel/api/instance/TickableInstance.java index efb2fedb1..488ba8697 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/TickableInstance.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/TickableInstance.java @@ -38,7 +38,7 @@ public interface TickableInstance extends Instance { *
You might want to opt out of this if you want your animations to remain smooth * even when far away from the camera. It is recommended to keep this as is, however. * - * @return true if your instance should be slow ticked. + * @return {@code true} if your instance should be slow ticked. */ default boolean decreaseTickRateWithDistance() { return true; diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java index 1ec315fa9..4f194e5d9 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java @@ -12,10 +12,17 @@ public class GlVertexArray extends GlObject { setHandle(GlStateManager._glGenVertexArrays()); } + public static void bind(int vao) { + GlStateManager._glBindVertexArray(vao); + BufferUploaderAccessor.flywheel$setLastVAO(vao); + } + public void bind() { - int handle = handle(); - GlStateManager._glBindVertexArray(handle); - BufferUploaderAccessor.flywheel$setLastVAO(handle); + bind(handle()); + } + + public static int getBoundVertexArray() { + return BufferUploaderAccessor.flywheel$getLastVAO(); } public static void unbind() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBufferType.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBufferType.java index 53a0ab9ac..16f0c450a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBufferType.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBufferType.java @@ -50,4 +50,12 @@ public enum GlBufferType { case GL15C.GL_ARRAY_BUFFER -> BufferUploaderAccessor.flywheel$setLastVBO(0); } } + + public int getBoundBuffer() { + return switch (this.glEnum) { + case GL15C.GL_ELEMENT_ARRAY_BUFFER -> BufferUploaderAccessor.flywheel$getLastEBO(); + case GL15C.GL_ARRAY_BUFFER -> BufferUploaderAccessor.flywheel$getLastVBO(); + default -> -1; + }; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlVersioned.java b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlVersioned.java index d019832b7..8615e9086 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlVersioned.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlVersioned.java @@ -4,7 +4,7 @@ import org.lwjgl.opengl.GLCapabilities; /** * This interface should be implemented by enums such that the - * last defined variant always returns true. + * last defined variant always returns {@code true} */ public interface GlVersioned { /** diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstance.java index 1a2ebb781..6a3e67ba8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstance.java @@ -65,13 +65,13 @@ public abstract class AbstractInstance implements Instance, LightListener { * When an instance is reset, the instance is deleted and re-created. * *

- * Just before {@link #update()} would be called, shouldReset() is checked. - * If this function returns true, then this instance will be {@link #remove removed}, + * Just before {@link #update()} would be called, {@code shouldReset()} is checked. + * If this function returns {@code true}, then this instance will be {@link #remove removed}, * and another instance will be constructed to replace it. This allows for more sane resource * acquisition compared to trying to update everything within the lifetime of an instance. *

* - * @return true if this instance should be discarded and refreshed. + * @return {@code true} if this instance should be discarded and refreshed. */ public boolean shouldReset() { return false; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java index 11925664f..ed4313063 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java @@ -48,12 +48,12 @@ public abstract class BlockEntityInstance extends Abstrac } /** - * Just before {@link #update()} would be called, shouldReset() is checked. - * If this function returns true, then this instance will be {@link #remove removed}, + * Just before {@link #update()} would be called, {@code shouldReset()} is checked. + * If this function returns {@code true}, then this instance will be {@link #remove removed}, * and another instance will be constructed to replace it. This allows for more sane resource * acquisition compared to trying to update everything within the lifetime of an instance. * - * @return true if this instance should be discarded and refreshed. + * @return {@code true} if this instance should be discarded and refreshed. */ public boolean shouldReset() { return blockEntity.getBlockState() != blockState; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index b14cf78e7..8f044c733 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -79,6 +79,10 @@ public class InstancingEngine

implements Engine { */ @Override public void render(TaskEngine taskEngine, RenderLayerEvent event) { + int ebo = GlBufferType.ELEMENT_ARRAY_BUFFER.getBoundBuffer(); + int vbo = GlBufferType.ARRAY_BUFFER.getBoundBuffer(); + int vao = GlVertexArray.getBoundVertexArray(); + double camX; double camY; double camZ; @@ -99,9 +103,9 @@ public class InstancingEngine

implements Engine { getGroupsToRender(event.getLayer()).forEach(group -> group.render(viewProjection, camX, camY, camZ)); - GlBufferType.ELEMENT_ARRAY_BUFFER.unbind(); - GlBufferType.ARRAY_BUFFER.unbind(); - GlVertexArray.unbind(); + GlBufferType.ELEMENT_ARRAY_BUFFER.bind(ebo); + GlBufferType.ARRAY_BUFFER.bind(vbo); + GlVertexArray.bind(vao); } private Stream> getGroupsToRender(@Nullable RenderLayer layer) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java index ab055553d..24a8d1836 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java @@ -217,7 +217,7 @@ public class SourceFile { } /** - * Scan the source for #use "..." directives. + * Scan the source for {@code #use "..."} directives. * Records the contents of the directive into an {@link Import} object, and marks the directive for elision. * @param elisions */ diff --git a/src/main/java/com/jozufozu/flywheel/core/materials/FlatLit.java b/src/main/java/com/jozufozu/flywheel/core/materials/FlatLit.java index 038a7250a..3829a1a84 100644 --- a/src/main/java/com/jozufozu/flywheel/core/materials/FlatLit.java +++ b/src/main/java/com/jozufozu/flywheel/core/materials/FlatLit.java @@ -14,14 +14,14 @@ public interface FlatLit> { /** * @param blockLight An integer in the range [0, 15] representing the * amount of block light this instance should receive. - * @return this + * @return {@code this} */ D setBlockLight(int blockLight); /** * @param skyLight An integer in the range [0, 15] representing the * amount of sky light this instance should receive. - * @return this + * @return {@code this} */ D setSkyLight(int skyLight); diff --git a/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java b/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java index b3e96aa7d..c350361c9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java @@ -16,7 +16,7 @@ public class WorldModel implements Model { private final String name; /** - * It is expected that renderWorld.getShade(...) returns a constant. + * It is expected that {@code renderWorld.getShade(...)} returns a constant. */ public WorldModel(BlockAndTintGetter renderWorld, RenderType layer, Collection blocks, String name) { reader = Formats.BLOCK.createReader(ModelUtil.getBufferBuilderFromTemplate(renderWorld, layer, blocks)); diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java b/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java index 3716caef2..e293a2732 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java @@ -15,11 +15,11 @@ import net.minecraft.resources.ResourceLocation; * An object describing a shader program that can be loaded by flywheel. * *

- * These are defined through json. All ProgramSpecs in assets/modid/flywheel/programs are parsed and + * These are defined through json. All ProgramSpecs in {@code assets/modid/flywheel/programs} are parsed and * processed. One ProgramSpec typically specifies one "material" that can be used in game to render things. *

*

- * All shader source files in assets/modid/flywheel/shaders are completely loaded and parsed into + * All shader source files in {@code assets/modid/flywheel/shaders} are completely loaded and parsed into * {@link SourceFile SourceFiles}, but not compiled until one of them is * referenced by a ProgramSpec. *

diff --git a/src/main/java/com/jozufozu/flywheel/mixin/BufferUploaderAccessor.java b/src/main/java/com/jozufozu/flywheel/mixin/BufferUploaderAccessor.java index 64b81bd2b..f7d609805 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/BufferUploaderAccessor.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/BufferUploaderAccessor.java @@ -21,4 +21,19 @@ public interface BufferUploaderAccessor { static void flywheel$setLastEBO(int id) { throw new AssertionError(); } + + @Accessor("lastIndexBufferObject") + static int flywheel$getLastEBO() { + throw new AssertionError(); + } + + @Accessor("lastVertexBufferObject") + static int flywheel$getLastVBO() { + throw new AssertionError(); + } + + @Accessor("lastVertexArrayObject") + static int flywheel$getLastVAO() { + throw new AssertionError(); + } } From 5c4ff9ca2a6021880803ed4e796a79e77154cf7b Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Wed, 5 Jan 2022 22:01:03 -0800 Subject: [PATCH 2/2] Fix visual artifacts with contraptions while using opfine. I think the buffers from the shadow pass were bleeding into the color pass. --- .../jozufozu/flywheel/backend/Backend.java | 8 +-- .../flywheel/backend/OptifineHandler.java | 25 +++++++ .../backend/instancing/InstanceWorld.java | 6 +- .../flywheel/core/LastActiveCamera.java | 16 +++++ .../flywheel/event/BeginFrameEvent.java | 20 +++--- .../jozufozu/flywheel/mixin/CameraMixin.java | 21 ++++++ .../jozufozu/flywheel/mixin/FrustumMixin.java | 25 +++++++ ...ooksMixin.java => LevelRendererMixin.java} | 4 +- src/main/resources/flywheel.mixins.json | 66 ++++++++++--------- 9 files changed, 138 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/core/LastActiveCamera.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/CameraMixin.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/FrustumMixin.java rename src/main/java/com/jozufozu/flywheel/mixin/{RenderHooksMixin.java => LevelRendererMixin.java} (95%) diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index bffbddc46..2285f5684 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -1,10 +1,6 @@ package com.jozufozu.flywheel.backend; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import javax.annotation.Nullable; @@ -55,7 +51,7 @@ public class Backend { * (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use. */ public String getBackendDescriptor() { - return engine.getProperName(); + return engine == null ? "" : engine.getProperName(); } public FlwEngine getEngine() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java b/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java index f003208fe..51e60eebe 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/OptifineHandler.java @@ -4,7 +4,11 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.lang.reflect.Field; import java.util.Optional; +import java.util.function.BooleanSupplier; + +import com.jozufozu.flywheel.util.Lazy; import net.minecraft.client.Minecraft; @@ -15,6 +19,23 @@ public class OptifineHandler { private static Package optifine; private static OptifineHandler handler; + private static final Lazy isShadowPass = Lazy.of(() -> { + try { + Class ofShaders = Class.forName("net.optifine.shaders.Shaders"); + Field field = ofShaders.getDeclaredField("isShadowPass"); + field.setAccessible(true); + return () -> { + try { + return field.getBoolean(null); + } catch (IllegalAccessException ignored) { + return false; + } + }; + } catch (Exception ignored) { + return () -> false; + } + }); + public final boolean usingShaders; public OptifineHandler(boolean usingShaders) { @@ -40,6 +61,10 @@ public class OptifineHandler { .orElse(false); } + public static boolean isShadowPass() { + return isShadowPass.get().getAsBoolean(); + } + public static void init() { optifine = Package.getPackage(OPTIFINE_ROOT_PACKAGE); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index 1f4c7200c..8274a2e06 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -90,12 +90,12 @@ public class InstanceWorld { *

*/ public void beginFrame(BeginFrameEvent event) { - engine.beginFrame(event.getInfo()); + engine.beginFrame(event.getCamera()); taskEngine.syncPoint(); - blockEntityInstanceManager.beginFrame(taskEngine, event.getInfo()); - entityInstanceManager.beginFrame(taskEngine, event.getInfo()); + blockEntityInstanceManager.beginFrame(taskEngine, event.getCamera()); + entityInstanceManager.beginFrame(taskEngine, event.getCamera()); } /** diff --git a/src/main/java/com/jozufozu/flywheel/core/LastActiveCamera.java b/src/main/java/com/jozufozu/flywheel/core/LastActiveCamera.java new file mode 100644 index 000000000..0d47d3c66 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/LastActiveCamera.java @@ -0,0 +1,16 @@ +package com.jozufozu.flywheel.core; + +import net.minecraft.client.Camera; + +public class LastActiveCamera { + + private static Camera camera; + + public static void _setActiveCamera(Camera camera) { + LastActiveCamera.camera = camera; + } + + public static Camera getActiveCamera() { + return camera; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/event/BeginFrameEvent.java b/src/main/java/com/jozufozu/flywheel/event/BeginFrameEvent.java index 2db6271ee..db4d6fd1f 100644 --- a/src/main/java/com/jozufozu/flywheel/event/BeginFrameEvent.java +++ b/src/main/java/com/jozufozu/flywheel/event/BeginFrameEvent.java @@ -8,28 +8,28 @@ import net.minecraftforge.eventbus.api.Event; public class BeginFrameEvent extends Event { private final ClientLevel world; - private final Camera info; - private final Frustum clippingHelper; + private final Camera camera; + private final Frustum frustum; - public BeginFrameEvent(ClientLevel world, Camera info, Frustum clippingHelper) { + public BeginFrameEvent(ClientLevel world, Camera camera, Frustum frustum) { this.world = world; - this.info = info; - this.clippingHelper = clippingHelper; + this.camera = camera; + this.frustum = frustum; } public ClientLevel getWorld() { return world; } - public Camera getInfo() { - return info; + public Camera getCamera() { + return camera; } - public Frustum getClippingHelper() { - return clippingHelper; + public Frustum getFrustum() { + return frustum; } public Vec3 getCameraPos() { - return info.getPosition(); + return camera.getPosition(); } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/CameraMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/CameraMixin.java new file mode 100644 index 000000000..52e6043ef --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/CameraMixin.java @@ -0,0 +1,21 @@ +package com.jozufozu.flywheel.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.jozufozu.flywheel.core.LastActiveCamera; + +import net.minecraft.client.Camera; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.BlockGetter; + +@Mixin(Camera.class) +public class CameraMixin { + + @Inject(method = "setup", at = @At("TAIL")) + private void setup(BlockGetter level, Entity entity, boolean is3rdPerson, boolean isMirrored, float pt, CallbackInfo ci) { + LastActiveCamera._setActiveCamera((Camera)(Object) this); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/FrustumMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/FrustumMixin.java new file mode 100644 index 000000000..c0edf6bf0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/FrustumMixin.java @@ -0,0 +1,25 @@ +package com.jozufozu.flywheel.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.jozufozu.flywheel.backend.OptifineHandler; +import com.jozufozu.flywheel.core.LastActiveCamera; +import com.jozufozu.flywheel.event.BeginFrameEvent; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraftforge.common.MinecraftForge; + +@Mixin(Frustum.class) +public class FrustumMixin { + + @Inject(method = "prepare", at = @At("TAIL")) + private void onPrepare(double x, double y, double z, CallbackInfo ci) { + if (OptifineHandler.isShadowPass()) { + MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(Minecraft.getInstance().level, LastActiveCamera.getActiveCamera(), (Frustum) (Object) this)); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/RenderHooksMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java similarity index 95% rename from src/main/java/com/jozufozu/flywheel/mixin/RenderHooksMixin.java rename to src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java index a60ffd45d..3dbe19701 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/RenderHooksMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java @@ -33,7 +33,7 @@ import net.minecraftforge.common.MinecraftForge; @OnlyIn(Dist.CLIENT) @Mixin(LevelRenderer.class) -public class RenderHooksMixin { +public class LevelRendererMixin { @Shadow private ClientLevel level; @@ -52,7 +52,7 @@ public class RenderHooksMixin { * layer-correct custom rendering. RenderWorldLast is not refined enough for rendering world objects. * This should probably be a forge event. */ - @Inject(at = @At("TAIL"), method = "renderChunkLayer") + @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ShaderInstance;clear()V"), method = "renderChunkLayer") private void renderLayer(RenderType type, PoseStack stack, double camX, double camY, double camZ, Matrix4f p_172999_, CallbackInfo ci) { RenderBuffers renderBuffers = this.renderBuffers; diff --git a/src/main/resources/flywheel.mixins.json b/src/main/resources/flywheel.mixins.json index bcc9860ab..01959c480 100644 --- a/src/main/resources/flywheel.mixins.json +++ b/src/main/resources/flywheel.mixins.json @@ -1,34 +1,36 @@ { - "required": true, - "minVersion": "0.8", - "package": "com.jozufozu.flywheel.mixin", - "compatibilityLevel": "JAVA_17", - "refmap": "flywheel.refmap.json", - "client": [ - "BlockEntityTypeMixin", - "BufferBuilderMixin", - "BufferUploaderAccessor", - "CancelEntityRenderMixin", - "ChunkRebuildHooksMixin", - "EntityTypeMixin", - "FixFabulousDepthMixin", - "InstanceAddMixin", - "InstanceRemoveMixin", - "LevelRendererAccessor", - "PausedPartialTickAccessor", - "RenderHooksMixin", - "RenderTexturesMixin", - "ShaderCloseMixin", - "ShaderInstanceAccessor", - "atlas.AtlasDataMixin", - "atlas.SheetDataAccessor", - "light.LightUpdateMixin", - "light.NetworkLightUpdateMixin", - "matrix.Matrix3fMixin", - "matrix.Matrix4fMixin", - "matrix.PoseStackMixin" - ], - "injectors": { - "defaultRequire": 1 - } + "required": true, + "minVersion": "0.8", + "package": "com.jozufozu.flywheel.mixin", + "compatibilityLevel": "JAVA_17", + "refmap": "flywheel.refmap.json", + "client": [ + "BlockEntityTypeMixin", + "BufferBuilderMixin", + "BufferUploaderAccessor", + "CameraMixin", + "CancelEntityRenderMixin", + "ChunkRebuildHooksMixin", + "EntityTypeMixin", + "FixFabulousDepthMixin", + "FrustumMixin", + "InstanceAddMixin", + "InstanceRemoveMixin", + "LevelRendererAccessor", + "LevelRendererMixin", + "PausedPartialTickAccessor", + "RenderTexturesMixin", + "ShaderCloseMixin", + "ShaderInstanceAccessor", + "atlas.AtlasDataMixin", + "atlas.SheetDataAccessor", + "light.LightUpdateMixin", + "light.NetworkLightUpdateMixin", + "matrix.Matrix3fMixin", + "matrix.Matrix4fMixin", + "matrix.PoseStackMixin" + ], + "injectors": { + "defaultRequire": 1 + } }