Skip to content

Commit

Permalink
Rewrite it so I can add any biped more easily, fixes #6
Browse files Browse the repository at this point in the history
Rewrite the detection to not use a hacky stack trace checker
Allows us to be more precise on specifically WHO this entity renderer belongs to, fixing #6.
Known issues:
- Some parts of the player render solid red when hurt
- Smart Moving causes the entire player renderer to break down and spams GL errors in the chat. Is there any possible solution I can throw at this mod that doesn't fucking break it?!

Signed-off-by: roadhog360 <[email protected]>
  • Loading branch information
Roadhog360 committed Sep 9, 2024
1 parent 67643c8 commit 4957631
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.client.event.RenderLivingEvent;
import roadhog360.simpleskinbackport.core.Utils;
import roadhog360.simpleskinbackport.ducks.IArmsState;
import roadhog360.simpleskinbackport.ducks.INewBipedModel;

Expand All @@ -26,6 +27,7 @@ public void onHandRender(RenderHandEvent event) {
@SubscribeEvent
public void onRenderEntity(RenderLivingEvent.Pre event) {
checkAndSetArmsState(event.entity, event.renderer);

ItemStack itemstack = event.entity.getEquipmentInSlot(4);
boolean showHeadwear = itemstack == null || !isHead(itemstack.getItem());
if(event.renderer instanceof RenderPlayer renderPlayer) {
Expand All @@ -36,16 +38,18 @@ public void onRenderEntity(RenderLivingEvent.Pre event) {
}

private void checkAndSetArmsState(Entity entity, Render render) {
ModelBiped modelBiped;
ModelBiped modelBiped = null;
if(render instanceof RenderPlayer renderPlayer) {
modelBiped = renderPlayer.modelBipedMain;
} else if (render instanceof RenderBiped renderBiped) {
modelBiped = renderBiped.modelBipedMain;
} else {
return;
}
if(modelBiped instanceof INewBipedModel model && entity instanceof IArmsState player) {
model.simpleSkinBackport$setSlim(player.simpleSkinBackport$isSlim());
if(modelBiped instanceof INewBipedModel model) {
if(entity instanceof IArmsState player) {
model.simpleSkinBackport$setSlim(player.simpleSkinBackport$isSlim());
} else if(Utils.rendererCopiesPlayerSkin(render)) {
model.simpleSkinBackport$setSlim(Utils.isClientPlayerSlim());
}
}
}

Expand Down
39 changes: 11 additions & 28 deletions src/main/java/roadhog360/simpleskinbackport/core/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelBox;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.resources.SkinManager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.MathHelper;
import roadhog360.simpleskinbackport.configuration.configs.ConfigModCompat;
import roadhog360.simpleskinbackport.ducks.IArmsState;
import roadhog360.simpleskinbackport.ducks.IBoxSizeGetter;
import roadhog360.simpleskinbackport.ducks.ITransparentBox;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -55,28 +57,6 @@ public static boolean isPlayer(MinecraftProfileTexture.Type type, SkinManager.Sk
return type == MinecraftProfileTexture.Type.SKIN && callback instanceof EntityPlayer;
}

public static boolean isCallerAssignableFrom(Class<?>... assignables) {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
return Arrays.stream(stElements, 4, stElements.length).anyMatch(
element -> Arrays.stream(assignables).anyMatch(
assignable -> {
try {
return assignable.isAssignableFrom(Class.forName(element.getClassName()));
} catch (ClassNotFoundException ignored) {
return false;
}
})
);
}

public static boolean isCallerNameEqualTo(String... assignables) {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
return Arrays.stream(stElements, 4, stElements.length).anyMatch(
element -> Arrays.stream(assignables).anyMatch(
assignable -> assignable.equals(element.getClassName()))
);
}

public static ModelRenderer setAllChildBoxesTransparent(ModelRenderer renderer) {
renderer.childModels.forEach(Utils::setAllBoxesTransparent);
return renderer;
Expand Down Expand Up @@ -127,17 +107,15 @@ public static ModelRenderer cloneModel(ModelBase base, ModelRenderer from, int t
}

public static ModelBox cloneBox(ModelBox box, ModelRenderer to, BoxTransformType transform) {
float size = 0;
float boxMinX = box.posX1;
float boxMinY = box.posY1;
float boxMinZ = box.posZ1;
int boxMaxX = MathHelper.floor_float(box.posX2 - box.posX1);
int boxMaxY = MathHelper.floor_float(box.posY2 - box.posY1);
int boxMaxZ = MathHelper.floor_float(box.posZ2 - box.posZ1);
//The size value gets baked into the box. We need to do this to not lose precision
float precision = Math.max(Math.max(boxMinX % 1, boxMinY % 1), boxMinZ % 1);
if(Math.abs(precision) > 0.001) {
size = precision;
float size = 0;
if(box instanceof IBoxSizeGetter boxWithSize) {
size = boxWithSize.simpleSkinBackport$getSize();
}
if(transform.isHatLayer()) {
size += 0.25F;
Expand Down Expand Up @@ -196,6 +174,11 @@ public static boolean isClientPlayerSlim() {
return false;
}

public static boolean rendererCopiesPlayerSkin(Render renderer) {
return renderer.getClass().getName().equals("vazkii.botania.client.render.entity.RenderDoppleganger")
|| (ConfigModCompat.TFgiantSkinSet == null && renderer.getClass().getName().equals("twilightforest.client.renderer.entity.RenderTFGiant"));
}

/**
* I got sick of constantly updating the util funcs whenever I needed to pass in a new setting lol
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package roadhog360.simpleskinbackport.ducks;

public interface IBoxSizeGetter {
float simpleSkinBackport$getSize();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@

public interface INewBipedModel {
void simpleSkinBackport$setSlim(boolean slim);
boolean simpleSkinBackport$isPlayerModel();
void simpleSkinBackport$setPlayerModel(boolean player);
void simpleSkinBackport$set64x();
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public List<String> getMixins(Set<String> loadedCoreMods) {
mixins.add("MixinModelSkull");
mixins.add("MixinModelBox");
mixins.add("MixinSkinManager");
mixins.add("MixinRenderingRegistry");
}
return mixins;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.gtnewhorizon.gtnhmixins.LateMixin;
import org.spongepowered.asm.mixin.MixinEnvironment;
import roadhog360.simpleskinbackport.SimpleSkinBackport;
import roadhog360.simpleskinbackport.configuration.configs.ConfigModCompat;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -24,12 +25,13 @@ public List<String> getMixins(Set<String> loadedMods) {
List<String> mixins = new ArrayList<>();
if(SIDE == MixinEnvironment.Side.CLIENT) {
if(loadedMods.contains("TwilightForest")) {
mixins.add("twilightforest.MixinRenderTFGiant");
if(ConfigModCompat.TFgiantSkinSet != null) {
mixins.add("twilightforest.MixinRenderTFGiant");
}
}
if(loadedMods.contains("Botania")) {
mixins.add("botania.MixinClientProxy");
mixins.add("botania.MixinRenderTileSkullOverride");
mixins.add("botania.MixinRenderDoppelganger");
}
}
return mixins;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
package roadhog360.simpleskinbackport.mixins.early;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.client.renderer.entity.RenderPlayer;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import roadhog360.simpleskinbackport.configuration.configs.ConfigMain;
import roadhog360.simpleskinbackport.core.ArmPair;
import roadhog360.simpleskinbackport.core.Utils;
Expand All @@ -22,15 +14,12 @@
@Mixin(ModelBiped.class)
public abstract class MixinModelBiped extends ModelBase implements INewBipedModel {

@Shadow
public ModelRenderer bipedHead;
@Shadow public ModelRenderer bipedHeadwear;
@Shadow public ModelRenderer bipedBody;
@Shadow public ModelRenderer bipedRightArm;
@Shadow public ModelRenderer bipedLeftArm;
@Shadow public ModelRenderer bipedRightLeg;
@Shadow public ModelRenderer bipedLeftLeg;
@Shadow public ModelRenderer bipedEars;
@Shadow public ModelRenderer bipedCloak;

//new stuff
Expand All @@ -46,43 +35,6 @@ public abstract class MixinModelBiped extends ModelBase implements INewBipedMode
@Unique
public ModelRenderer simpleSkinBackport$bipedBodyWear;

@Unique
private boolean simpleSkinBackport$isPlayerModel;


@WrapOperation(method = "<init>(FFII)V", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target="Lnet/minecraft/client/model/ModelBiped;textureHeight:I"))
private void checkPlayerModelAndSetDim(ModelBiped instance, int value, Operation<Void> original, @Local(ordinal = 0, argsOnly = true) float size) {
original.call(instance, simpleSkinBackport$isPlayerModel() ? 64 : value);

if(!simpleSkinBackport$isPlayerModel()) {
boolean isPlayerRenderer;
boolean isGaia;
//Do all this OUTSIDE of the if bracket, so we can find and add cases for classes that use size > 0
isGaia = Utils.isCallerNameEqualTo("vazkii.botania.client.render.entity.RenderDoppleganger");
isPlayerRenderer = Utils.isCallerAssignableFrom(RenderPlayer.class) || isGaia
|| Utils.isCallerNameEqualTo("twilightforest.client.renderer.entity.RenderTFGiant");
//We need a way to check if it's a player model, without modifying the RenderPlayer.

if (size == 0 || size == 0.0625F || isGaia) {
//TODO: Might have to add special exceptions for big models, I think this is model size so I named it as such.
// Mods that add giant (or small) players will need special treatment.
if (isPlayerRenderer) {
original.call(instance, 64);
simpleSkinBackport$setPlayerModel(true);
}
}
}
}

@Inject(method = "<init>(FFII)V", at = @At("TAIL"))
private void injectNewLimbs(float size, float p_i1149_2_, int texWidth, int texHeight, CallbackInfo ci) {
if (simpleSkinBackport$isPlayerModel() && textureWidth == 64 && (textureHeight == 32 || textureHeight == 64)) {
Utils.setAllBoxesTransparent(bipedHeadwear);
simpleSkinBackport$setupBoxes();
simpleSkinBackport$createArmBoxes();
}
}

@Unique
private ArmPair simpleSkinBackport$wideArms;
@Unique
Expand All @@ -96,8 +48,24 @@ private void injectNewLimbs(float size, float p_i1149_2_, int texWidth, int texH
@Unique
private float simpleSkinBackport$armsRotationPointY;

/**
* Resizes a model's boxes from a 32x64 texture to a 64x64 texture.
*/
public void simpleSkinBackport$set64x() {
if(textureHeight == 32) {
textureHeight = 64;

Utils.changeTextureSize(this, textureWidth, 64);

simpleSkinBackport$setupBoxes();
simpleSkinBackport$createArmBoxes();
}
}

@Unique
private void simpleSkinBackport$setupBoxes() {
Utils.setAllBoxesTransparent(bipedHeadwear);

if(textureHeight == 64) {
Utils.remakeBoxes(bipedCloak.setTextureSize(textureWidth, 32));

Expand All @@ -117,79 +85,58 @@ private void injectNewLimbs(float size, float p_i1149_2_, int texWidth, int texH

simpleSkinBackport$bipedBodyWear = Utils.cloneModel(this, bipedBody, 16, 32, true, Utils.BoxTransformType.HAT);
}

simpleSkinBackport$armsRotationPointY = bipedRightArm.rotationPointY;
}

/**
* Creates the ModelBox instances used for slim arms. Creates dummy models currently, this could probably be more efficient...
* Creates the ModelBox instances used for slim arms.
*/
@Unique
private void simpleSkinBackport$createArmBoxes() {
ModelRenderer tempLeftArmSlim = Utils.cloneModel(this, bipedLeftArm, false, Utils.BoxTransformType.SLIM_ARM);
ModelRenderer tempRightArmSlim = Utils.cloneModel(this, bipedRightArm, false, Utils.BoxTransformType.SLIM_RIGHT_ARM);
ModelRenderer tempLeftArmwearSlim = Utils.setAllBoxesTransparent(Utils.cloneModel(
this, bipedLeftArm, 48, 48, false, Utils.BoxTransformType.SLIM_ARM_HAT));
ModelRenderer tempRightArmwearSlim = Utils.setAllBoxesTransparent(Utils.cloneModel(
this, bipedRightArm, 40, 32, false, Utils.BoxTransformType.SLIM_RIGHT_ARM_HAT));

simpleSkinBackport$wideArms = ArmPair.of(bipedLeftArm, bipedRightArm);
simpleSkinBackport$slimArms = ArmPair.of(tempLeftArmSlim, tempRightArmSlim);

simpleSkinBackport$wideArmwear = ArmPair.of(simpleSkinBackport$bipedLeftArmwear, simpleSkinBackport$bipedRightArmwear);
simpleSkinBackport$slimArmwear = ArmPair.of(tempLeftArmwearSlim, tempRightArmwearSlim);

simpleSkinBackport$armsRotationPointY = bipedLeftArm.rotationPointY;
}

private void simpleSkinBackport$set64x() {
if(textureHeight == 32) {
textureHeight = 64;

Utils.changeTextureSize(this, textureWidth, 64);

Utils.remakeBoxes(bipedRightArm);
Utils.remakeBoxes(bipedRightLeg);

simpleSkinBackport$setupBoxes();
simpleSkinBackport$createArmBoxes();
if(textureHeight == 64) {
ModelRenderer tempLeftArmwearSlim = Utils.setAllBoxesTransparent(Utils.cloneModel(
this, bipedLeftArm, 48, 48, false, Utils.BoxTransformType.SLIM_ARM_HAT));
ModelRenderer tempRightArmwearSlim = Utils.setAllBoxesTransparent(Utils.cloneModel(
this, bipedRightArm, 40, 32, false, Utils.BoxTransformType.SLIM_RIGHT_ARM_HAT));
simpleSkinBackport$wideArmwear = ArmPair.of(simpleSkinBackport$bipedLeftArmwear, simpleSkinBackport$bipedRightArmwear);
simpleSkinBackport$slimArmwear = ArmPair.of(tempLeftArmwearSlim, tempRightArmwearSlim);
}
}

@Override
public void simpleSkinBackport$setSlim(boolean slim) {
// if(!simpleSkinBackport$isPlayerModel()) {
// simpleSkinBackport$set64x();
// simpleSkinBackport$setPlayerModel(true);
// }
if(simpleSkinBackport$isPlayerModel()) {
if (ConfigMain.oldSlimArms) {
if (slim) {
bipedLeftArm.rotationPointY = simpleSkinBackport$armsRotationPointY + 0.5F;
bipedRightArm.rotationPointY = simpleSkinBackport$armsRotationPointY + 0.5F;
} else {
bipedLeftArm.rotationPointY = simpleSkinBackport$armsRotationPointY;
bipedRightArm.rotationPointY = simpleSkinBackport$armsRotationPointY;
}
if(simpleSkinBackport$slimArms == null || simpleSkinBackport$wideArms == null) {
simpleSkinBackport$createArmBoxes();
}
ArmPair arms = slim ? simpleSkinBackport$slimArms : simpleSkinBackport$wideArms;
if (ConfigMain.oldSlimArms) {
if (slim) {
bipedLeftArm.rotationPointY = simpleSkinBackport$armsRotationPointY + 0.5F;
bipedRightArm.rotationPointY = simpleSkinBackport$armsRotationPointY + 0.5F;
} else {
bipedLeftArm.rotationPointY = simpleSkinBackport$armsRotationPointY;
bipedRightArm.rotationPointY = simpleSkinBackport$armsRotationPointY;
}
ArmPair arms = slim ? simpleSkinBackport$slimArms : simpleSkinBackport$wideArms;
}
bipedLeftArm.displayList = arms.getLeftDisplayList();
bipedRightArm.displayList = arms.getRightDisplayList();
bipedLeftArm.cubeList = arms.getLeft();
bipedRightArm.cubeList = arms.getRight();
if(textureHeight == 64 && simpleSkinBackport$slimArmwear != null && simpleSkinBackport$wideArmwear != null) {
ArmPair armwear = slim ? simpleSkinBackport$slimArmwear : simpleSkinBackport$wideArmwear;
bipedLeftArm.displayList = arms.getLeftDisplayList();
bipedRightArm.displayList = arms.getRightDisplayList();
simpleSkinBackport$bipedLeftArmwear.displayList = armwear.getLeftDisplayList();
simpleSkinBackport$bipedRightArmwear.displayList = armwear.getRightDisplayList();
bipedLeftArm.cubeList = arms.getLeft();
bipedRightArm.cubeList = arms.getRight();
simpleSkinBackport$bipedLeftArmwear.cubeList = armwear.getLeft();
simpleSkinBackport$bipedRightArmwear.cubeList = armwear.getRight();
}
}

@Override
public boolean simpleSkinBackport$isPlayerModel() {
return simpleSkinBackport$isPlayerModel;
}

@Override
public void simpleSkinBackport$setPlayerModel(boolean player) {
simpleSkinBackport$isPlayerModel = player;
}
}
Loading

0 comments on commit 4957631

Please sign in to comment.