Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public class FixesConfig {
@Config.DefaultBoolean(true)
public static boolean fixBogusIntegratedServerNPEs;

@Config.Comment("Do not flip bottom face textures (1.8+ behavior, see MC-47811)")
@Config.DefaultBoolean(true)
public static boolean fixBottomFaceUV;

@Config.Comment("Fix wrapped chat lines missing colors")
@Config.DefaultBoolean(true)
public static boolean fixChatWrappedColors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public HodgepodgeCore() {
if (TweaksConfig.enableTagCompoundStringPooling || TweaksConfig.enableNBTStringPooling) {
StringPooler.setupPooler();
}
if (FixesConfig.fixBottomFaceUV) {
Launch.blackboard.put("hodgepodge.FixesConfig.fixBottomFaceUV", Boolean.TRUE);
}
} catch (ConfigException e) {
throw new RuntimeException(e);
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/mitchej123/hodgepodge/mixins/Mixins.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ public enum Mixins implements IMixins {
.addCommonMixins("minecraft.MixinBlockFence")
.setApplyIf(() -> FixesConfig.fixFenceConnections)
.setPhase(Phase.EARLY)),
FIX_BOTTOM_FACE_UV(new MixinBuilder()
.addClientMixins("minecraft.MixinRenderBlocks_FaceYNegUV")
.setApplyIf(() -> FixesConfig.fixBottomFaceUV)
.setPhase(Phase.EARLY)),
FIX_INVENTORY_OFFSET_WITH_POTIONS(new MixinBuilder()
.addClientMixins("minecraft.MixinInventoryEffectRenderer_PotionOffset")
.setApplyIf(() -> TweaksConfig.fixPotionRenderOffset)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package com.mitchej123.hodgepodge.mixins.early.minecraft;

import net.minecraft.block.Block;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.IIcon;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;

/**
* Patched {@link RenderBlocks} to fix {@link #renderFaceYNeg} texture UV
* <dl>
* <dt>Suppressed warnings:</dt>
* <dd>{@code ClassWithTooManyFields}: Legacy class design</dd>
* <dd>{@code UnusedMixin}: Dynamically applied at run-time</dd>
* </dl>
*/
@SuppressWarnings({ "ClassWithTooManyFields", "UnusedMixin" })
@Mixin(value = RenderBlocks.class, priority = 100)
public abstract class MixinRenderBlocks_FaceYNegUV {

@Shadow
public IIcon overrideBlockTexture;
@Shadow
public double renderMinX, renderMaxX, renderMinZ, renderMaxZ, renderMinY;
@Shadow
public int uvRotateBottom;
@Shadow
public boolean renderFromInside;
@Shadow
public boolean enableAO;
@Shadow
public int brightnessTopLeft, brightnessTopRight, brightnessBottomLeft, brightnessBottomRight;
@Shadow
public float colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft;
@Shadow
public float colorRedTopRight, colorGreenTopRight, colorBlueTopRight;
@Shadow
public float colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft;
@Shadow
public float colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight;

@Shadow
public abstract boolean hasOverrideBlockTexture();

/**
* @author leagris
* @reason Fixes horizontal flip bug in bottom face textures prior to Minecraft 1.8.
* @link <a href="https://bugs.mojang.com/browse/MC-47811">MC-47811</a>
*/
@SuppressWarnings("OverlyComplexMethod") // Complex by nature
@Overwrite
public void renderFaceYNeg(Block block, double x, double y, double z, IIcon icon) {
Tessellator tessellator = Tessellator.instance;

if (this.hasOverrideBlockTexture()) {
icon = this.overrideBlockTexture;
}

double uMinX = icon.getInterpolatedU(16.0D - this.renderMinX * 16.0D);
double uMaxX = icon.getInterpolatedU(16.0D - this.renderMaxX * 16.0D);
double vMinZ = icon.getInterpolatedV(this.renderMinZ * 16.0D);
double vMaxZ = icon.getInterpolatedV(this.renderMaxZ * 16.0D);

if (this.renderMinX < 0.0D || this.renderMaxX > 1.0D) {
uMinX = icon.getMaxU();
uMaxX = icon.getMinU();
}

if (this.renderMinZ < 0.0D || this.renderMaxZ > 1.0D) {
vMinZ = icon.getMinV();
vMaxZ = icon.getMaxV();
}

double uMaxXCopy = uMaxX;
double uMinXCopy = uMinX;
double vMinZCopy = vMinZ;
double vMaxZCopy = vMaxZ;

if (this.uvRotateBottom == 2) {
uMinX = icon.getInterpolatedU(16.0D - this.renderMinZ * 16.0D);
vMinZ = icon.getInterpolatedV(16.0D - this.renderMaxX * 16.0D);
uMaxX = icon.getInterpolatedU(16.0D - this.renderMaxZ * 16.0D);
vMaxZ = icon.getInterpolatedV(16.0D - this.renderMinX * 16.0D);
vMinZCopy = vMinZ;
vMaxZCopy = vMaxZ;
uMaxXCopy = uMinX;
uMinXCopy = uMaxX;
vMinZ = vMaxZ;
vMaxZ = vMinZCopy;
} else if (this.uvRotateBottom == 1) {
uMinX = icon.getInterpolatedU(this.renderMaxZ * 16.0D);
vMinZ = icon.getInterpolatedV(this.renderMinX * 16.0D);
uMaxX = icon.getInterpolatedU(this.renderMinZ * 16.0D);
vMaxZ = icon.getInterpolatedV(this.renderMaxX * 16.0D);
uMaxXCopy = uMaxX;
uMinXCopy = uMinX;
uMinX = uMaxX;
uMaxX = uMinXCopy;
vMinZCopy = vMaxZ;
vMaxZCopy = vMinZ;
} else if (this.uvRotateBottom == 3) {
uMinX = icon.getInterpolatedU(this.renderMinX * 16.0D);
uMaxX = icon.getInterpolatedU(this.renderMaxX * 16.0D);
vMinZ = icon.getInterpolatedV(16.0D - this.renderMinZ * 16.0D);
vMaxZ = icon.getInterpolatedV(16.0D - this.renderMaxZ * 16.0D);
uMaxXCopy = uMaxX;
uMinXCopy = uMinX;
vMinZCopy = vMinZ;
vMaxZCopy = vMaxZ;
}

double xMin = x + this.renderMinX;
double xMax = x + this.renderMaxX;
double yMin = y + this.renderMinY;
double zMin = z + this.renderMinZ;
double zMax = z + this.renderMaxZ;

if (this.renderFromInside) {
xMin = x + this.renderMaxX;
xMax = x + this.renderMinX;
}

if (this.enableAO) {
tessellator.setColorOpaque_F(this.colorRedTopLeft, this.colorGreenTopLeft, this.colorBlueTopLeft);
tessellator.setBrightness(this.brightnessTopLeft);
tessellator.addVertexWithUV(xMin, yMin, zMax, uMinXCopy, vMaxZCopy);
tessellator.setColorOpaque_F(this.colorRedBottomLeft, this.colorGreenBottomLeft, this.colorBlueBottomLeft);
tessellator.setBrightness(this.brightnessBottomLeft);
tessellator.addVertexWithUV(xMin, yMin, zMin, uMinX, vMinZ);
tessellator
.setColorOpaque_F(this.colorRedBottomRight, this.colorGreenBottomRight, this.colorBlueBottomRight);
tessellator.setBrightness(this.brightnessBottomRight);
tessellator.addVertexWithUV(xMax, yMin, zMin, uMaxXCopy, vMinZCopy);
tessellator.setColorOpaque_F(this.colorRedTopRight, this.colorGreenTopRight, this.colorBlueTopRight);
tessellator.setBrightness(this.brightnessTopRight);
tessellator.addVertexWithUV(xMax, yMin, zMax, uMaxX, vMaxZ);
} else {
tessellator.addVertexWithUV(xMin, yMin, zMax, uMinXCopy, vMaxZCopy);
tessellator.addVertexWithUV(xMin, yMin, zMin, uMinX, vMinZ);
tessellator.addVertexWithUV(xMax, yMin, zMin, uMaxXCopy, vMinZCopy);
tessellator.addVertexWithUV(xMax, yMin, zMax, uMaxX, vMaxZ);
}
}
}