Skip to content

Commit

Permalink
Some RenderType fixes
Browse files Browse the repository at this point in the history
Co-Authored-By: coderbot <[email protected]>
Co-Authored-By: IMS <[email protected]>
  • Loading branch information
3 people committed Sep 7, 2023
1 parent 86850e3 commit 7bf003b
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,22 @@ public class OuterWrappedRenderType extends RenderType implements WrappableRende
private final RenderStateShard extra;
private final RenderType wrapped;

public OuterWrappedRenderType(String name, RenderType wrapped, RenderStateShard extra) {
private OuterWrappedRenderType(String name, RenderType wrapped, RenderStateShard extra) {
super(name, wrapped.format(), wrapped.mode(), wrapped.bufferSize(),
wrapped.affectsCrumbling(), shouldSortOnUpload(wrapped), wrapped::setupRenderState, wrapped::clearRenderState);

this.extra = extra;
this.wrapped = wrapped;
}

public static OuterWrappedRenderType wrapExactlyOnce(String name, RenderType wrapped, RenderStateShard extra) {
if (wrapped instanceof OuterWrappedRenderType) {
wrapped = ((OuterWrappedRenderType) wrapped).unwrap();
}

return new OuterWrappedRenderType(name, wrapped, extra);
}

@Override
public void setupRenderState() {
extra.setupRenderState();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public class MixinLevelRenderer {
to = @At(value = "INVOKE", target = "net/minecraft/client/renderer/LevelRenderer.renderHitOutline (Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/world/entity/Entity;DDDLnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V")
))
private RenderType iris$beginBlockOutline(RenderType type) {
return new OuterWrappedRenderType("iris:is_outline", type, IsOutlineRenderStateShard.INSTANCE);
return OuterWrappedRenderType.wrapExactlyOnce("iris:is_outline", type, IsOutlineRenderStateShard.INSTANCE);
}

@Inject(method = "renderLevel", at = @At(value = "CONSTANT", args = "stringValue=translucent"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
package net.coderbot.iris.mixin.entity_render_context;

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.mojang.blaze3d.vertex.PoseStack;

import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.coderbot.batchedentityrendering.impl.Groupable;
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
import net.coderbot.iris.fantastic.WrappingMultiBufferSource;
import net.coderbot.iris.layer.BlockEntityRenderStateShard;
import net.coderbot.iris.layer.OuterWrappedRenderType;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;

/**
* Wraps block entity rendering functions in order to create additional render layers
Expand All @@ -25,57 +21,44 @@
*/
@Mixin(BlockEntityRenderDispatcher.class)
public class MixinBlockEntityRenderDispatcher {
private static final String RENDER =
"render(Lnet/minecraft/block/entity/BlockEntity;FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;)V";

private static final String RUN_REPORTED =
"Lnet/minecraft/client/renderer/blockentity/BlockEntityRenderDispatcher;tryRender(Lnet/minecraft/world/level/block/entity/BlockEntity;Ljava/lang/Runnable;)V";

// I inject here in the method so that:
//
// 1. we can know that some checks we need have already been done
// 2. if someone cancels this method hopefully it gets cancelled before this point
@Inject(method = "render", at = @At(value = "INVOKE", target = RUN_REPORTED))
private void iris$beforeRender(BlockEntity blockEntity, float tickDelta, PoseStack poseStack,
MultiBufferSource bufferSource, CallbackInfo ci) {
if (!(bufferSource instanceof WrappingMultiBufferSource)) {
return;
// 2. if someone cancels this method hopefully it gets cancelled before this point, so we
// aren't running any redundant computations.
//
// NOTE: This is the last location that we can inject at, because the MultiBufferSource variable gets
// captured by the lambda shortly afterwards, and therefore our ModifyVariable call becomes ineffective!
@ModifyVariable(method = "render", at = @At(value = "INVOKE",
target = "net/minecraft/world/level/block/entity/BlockEntityType.isValid (Lnet/minecraft/world/level/block/Block;)Z"),
allow = 1, require = 1)
private MultiBufferSource iris$wrapBufferSource(MultiBufferSource bufferSource, BlockEntity blockEntity) {
if (!(bufferSource instanceof Groupable)) {
// Fully batched entity rendering is not being used, do not use this wrapper!!!
return bufferSource;
}

Object2IntMap<BlockState> blockStateIds = BlockRenderingSettings.INSTANCE.getBlockStateIds();

if (blockStateIds == null) {
return;
return bufferSource;
}

// At this point, based on where we are in BlockEntityRenderDispatcher:
// - The block entity is non-null
// - The block entity has a world
// - The block entity thinks that it's supported by a valid block

int intId = blockStateIds.getOrDefault(blockEntity.getBlockState(), -1);
RenderStateShard stateShard = BlockEntityRenderStateShard.forId(intId);
// - The block entity is not sure that it's supported by a valid block

((WrappingMultiBufferSource) bufferSource).pushWrappingFunction(type ->
new OuterWrappedRenderType("iris:is_block_entity", type, stateShard));
}

@Inject(method = "render", at = @At(value = "INVOKE", target = RUN_REPORTED, shift = At.Shift.AFTER))
private void iris$afterRender(BlockEntity blockEntity, float tickDelta, PoseStack matrix,
MultiBufferSource bufferSource, CallbackInfo ci) {
if (!(bufferSource instanceof WrappingMultiBufferSource)) {
return;
BlockState state = blockEntity.getBlockState();
if (!blockEntity.getType().isValid(state.getBlock())) {
return bufferSource;
}

// This might not get called if we crash and something like NotEnoughCrashes tries
// to act like nothing happened.
//
// Supporting that is hard so I decided to just ignore that for now.
//
// This might also not get called if a different mod cancels before runReported but
// after my inject, but I placed my inject there in the hopes that it would
// not be likely to be affected by a cancel. I hope that the universe doesn't
// conspire against me and cause that to break.
((WrappingMultiBufferSource) bufferSource).popWrappingFunction();
int intId = blockStateIds.getOrDefault(state, -1);
RenderStateShard stateShard = BlockEntityRenderStateShard.forId(intId);

return type ->
bufferSource.getBuffer(OuterWrappedRenderType.wrapExactlyOnce("iris:is_block_entity", type, stateShard));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
package net.coderbot.iris.mixin.entity_render_context;

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.mojang.blaze3d.vertex.PoseStack;

import it.unimi.dsi.fastutil.objects.Object2IntFunction;
import net.coderbot.batchedentityrendering.impl.Groupable;
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
import net.coderbot.iris.fantastic.WrappingMultiBufferSource;
import net.coderbot.iris.layer.EntityRenderStateShard;
import net.coderbot.iris.layer.OuterWrappedRenderType;
import net.coderbot.iris.shaderpack.materialmap.NamespacedId;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.registries.ForgeRegistries;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;

/**
* Wraps entity rendering functions in order to create additional render layers
Expand All @@ -27,66 +23,27 @@
*/
@Mixin(EntityRenderDispatcher.class)
public class MixinEntityRenderDispatcher {
private static final String CRASHREPORT_CREATE =
"Lnet/minecraft/world/entity/Entity;fillCrashReportCategory(Lnet/minecraft/CrashReportCategory;)V";

// Inject after MatrixStack#push to increase the chances that we won't be caught out by a poorly-positioned
// cancellation in an inject.
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V", shift = At.Shift.AFTER))
private void iris$beginEntityRender(Entity entity, double x, double y, double z, float yaw, float tickDelta,
PoseStack poseStack, MultiBufferSource bufferSource, int light,
CallbackInfo ci) {
if (!(bufferSource instanceof WrappingMultiBufferSource)) {
return;
// Inject after MatrixStack#push since at this point we know that most cancellation checks have already passed.
@ModifyVariable(method = "render", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V", shift = At.Shift.AFTER),
allow = 1, require = 1)
private MultiBufferSource iris$beginEntityRender(MultiBufferSource bufferSource, Entity entity) {
if (!(bufferSource instanceof Groupable)) {
// Fully batched entity rendering is not being used, do not use this wrapper!!!
return bufferSource;
}

ResourceLocation entityId = ForgeRegistries.ENTITIES.getKey(entity.getType());
ResourceLocation entityId = Registry.ENTITY_TYPE.getKey(entity.getType());

Object2IntFunction<NamespacedId> entityIds = BlockRenderingSettings.INSTANCE.getEntityIds();

if (entityIds == null) {
return;
return bufferSource;
}

int intId = entityIds.applyAsInt(new NamespacedId(entityId.getNamespace(), entityId.getPath()));
RenderStateShard phase = EntityRenderStateShard.forId(intId);

((WrappingMultiBufferSource) bufferSource).pushWrappingFunction(layer ->
new OuterWrappedRenderType("iris:is_entity", layer, phase));
}

// Inject before MatrixStack#pop so that our wrapper stack management operations naturally line up
// with vanilla's MatrixStack management functions.
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;popPose()V"))
private void iris$endEntityRender(Entity entity, double x, double y, double z, float yaw, float tickDelta,
PoseStack poseStack, MultiBufferSource bufferSource, int light,
CallbackInfo ci) {
if (!(bufferSource instanceof WrappingMultiBufferSource)) {
return;
}

((WrappingMultiBufferSource) bufferSource).popWrappingFunction();
}

@Inject(method = "render", at = @At(value = "INVOKE", target = CRASHREPORT_CREATE))
private void iris$crashedEntityRender(Entity entity, double x, double y, double z, float yaw, float tickDelta,
PoseStack poseStack, MultiBufferSource bufferSource, int light,
CallbackInfo ci) {
if (!(bufferSource instanceof WrappingMultiBufferSource)) {
return;
}

try {
// Try to avoid leaving the wrapping stack in a bad state if we crash.
// This will only be an issue with mods like NotEnoughCrashes that try
// to act like nothing happened when a fatal error occurs.
//
// This could fail if we crash before MatrixStack#push, but this is mostly
// a best-effort thing, it doesn't have to work perfectly. NEC will cause
// weird chaos no matter what we do.
((WrappingMultiBufferSource) bufferSource).popWrappingFunction();
} catch (Exception e) {
// oh well, we're gonna crash anyways.
}
return type ->
bufferSource.getBuffer(OuterWrappedRenderType.wrapExactlyOnce("iris:is_entity", type, phase));
}
}
}

0 comments on commit 7bf003b

Please sign in to comment.