(feature) 3d skins mod

This commit is contained in:
kirillsaint 2024-05-06 14:07:48 +06:00
parent 3444529aa7
commit 9aeb693478
23 changed files with 1470 additions and 70 deletions

View File

@ -11,12 +11,11 @@ import net.silentclient.client.gui.SilentScreen;
import net.silentclient.client.gui.animation.SimpleAnimation;
import net.silentclient.client.gui.animation.normal.Direction;
import net.silentclient.client.gui.elements.Button;
import net.silentclient.client.gui.lite.clickgui.utils.GlUtils;
import net.silentclient.client.gui.lite.clickgui.utils.MouseUtils;
import net.silentclient.client.gui.lite.clickgui.utils.MouseUtils.Scroll;
import net.silentclient.client.gui.elements.*;
import net.silentclient.client.gui.font.SilentFontRenderer;
import net.silentclient.client.gui.hud.HUDConfigScreen;
import net.silentclient.client.gui.lite.clickgui.utils.GlUtils;
import net.silentclient.client.gui.lite.clickgui.utils.MouseUtils;
import net.silentclient.client.gui.modmenu.CellGrid;
import net.silentclient.client.gui.theme.Theme;
import net.silentclient.client.gui.theme.input.DefaultInputTheme;
@ -27,10 +26,7 @@ import net.silentclient.client.mods.ModCategory;
import net.silentclient.client.mods.Setting;
import net.silentclient.client.mods.render.crosshair.CrosshairMod;
import net.silentclient.client.mods.world.TimeChangerMod;
import net.silentclient.client.utils.ColorUtils;
import net.silentclient.client.utils.MenuBlurUtils;
import net.silentclient.client.utils.MouseCursorHandler;
import net.silentclient.client.utils.Sounds;
import net.silentclient.client.utils.*;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
@ -45,6 +41,7 @@ public class ModSettings extends SilentScreen {
public double scrollY;
public static SimpleAnimation scrollAnimation = new SimpleAnimation(0.0F);
private ScrollHelper scrollHelper = new ScrollHelper();
public ModSettings(Mod mod, GuiScreen parent) {
if (mod == null) throw new IllegalArgumentException("Mod is null");
@ -130,8 +127,13 @@ public class ModSettings extends SilentScreen {
GL11.glPushMatrix();
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
int settingY = (int) (y + 25 + scrollAnimation.getValue() + mod.customComponentLiteHeight());
scrollHelper.setStep(5);
scrollHelper.setElementsHeight(25 + mod.customComponentHeight() + (Client.getInstance().getSettingsManager().getSettingByMod(mod).size() * 25));
scrollHelper.setMaxScroll(height);
scrollHelper.setSpeed(200);
scrollHelper.setFlag(true);
float scrollY = scrollHelper.getScroll();
int settingY = (int) (y + 25 + scrollY + mod.customComponentLiteHeight());
GL11.glPopMatrix();
@ -145,8 +147,8 @@ public class ModSettings extends SilentScreen {
int translatedY = r.getScaledHeight() - y - height;
GL11.glScissor(x * s, translatedY * s, this.width * s, height * s);
Client.getInstance().getSilentFontRenderer().drawString(mod.getName(), x + 100, (int) (y + 5) + scrollAnimation.getValue(), 14, SilentFontRenderer.FontType.TITLE);
MouseCursorHandler.CursorType cursorTypeCustom = mod.renderCustomLiteComponent(x + 100, (int) (y + 25 + scrollAnimation.getValue()), width, height, mouseX, mouseY);
Client.getInstance().getSilentFontRenderer().drawString(mod.getName(), x + 100, (y + 5) + scrollY, 14, SilentFontRenderer.FontType.TITLE);
MouseCursorHandler.CursorType cursorTypeCustom = mod.renderCustomLiteComponent(x + 100, (int) (y + 25 + scrollY), width, height, mouseX, mouseY);
if(cursorTypeCustom != null) {
cursorType = cursorTypeCustom;
}
@ -230,13 +232,13 @@ public class ModSettings extends SilentScreen {
settingY += settingHeight;
}
if(mod.getCategory() == ModCategory.MODS) {
RenderUtil.drawImage(new ResourceLocation("silentclient/icons/reset_settings.png"), x + width - (10 + 8) - 15, y + 5 + scrollAnimation.getValue(), 10, 10);
Tooltip.render(mouseX, mouseY, x + width - (10 + 8) - 15, y + 5 + scrollAnimation.getValue(), 10, 10, "Reset");
if(MouseUtils.isInside(mouseX, mouseY, x + width - (10 + 8) - 15, y + 5 + scrollAnimation.getValue(), 10, 10)) {
RenderUtil.drawImage(new ResourceLocation("silentclient/icons/reset_settings.png"), x + width - (10 + 8) - 15, y + 5 + scrollY, 10, 10);
Tooltip.render(mouseX, mouseY, x + width - (10 + 8) - 15, y + 5 + scrollY, 10, 10, "Reset");
if(MouseUtils.isInside(mouseX, mouseY, x + width - (10 + 8) - 15, y + 5 + scrollY, 10, 10)) {
cursorType = MouseCursorHandler.CursorType.POINTER;
}
Switch.render(mouseX, mouseY, x + width - (10 + 8), y + 6 + scrollAnimation.getValue(), mod.simpleAnimation, mod.isEnabled(), mod.isForceDisabled(), mod.isForceDisabled() ? "Force disabled" : null);
if(Switch.isHovered(mouseX, mouseY, x + width - (10 + 8), y + 6 + scrollAnimation.getValue())) {
Switch.render(mouseX, mouseY, x + width - (10 + 8), y + 6 + scrollY, mod.simpleAnimation, mod.isEnabled(), mod.isForceDisabled(), mod.isForceDisabled() ? "Force disabled" : null);
if(Switch.isHovered(mouseX, mouseY, x + width - (10 + 8), y + 6 + scrollY)) {
cursorType = MouseCursorHandler.CursorType.POINTER;
}
}
@ -245,45 +247,45 @@ public class ModSettings extends SilentScreen {
super.drawScreen(mouseX, mouseY, partialTicks);
final Scroll scroll = MouseUtils.scroll();
if(scroll != null) {
switch (scroll) {
case DOWN:
if(scrollY > -((settingIndex - 13.5) * 38)) {
scrollY -=12;
}
if(settingIndex > 13) {
if(scrollY < -((settingIndex - 15) * 38)) {
scrollY = -((settingIndex - 14.1) * 38);
}
}
if(mod.customComponentLiteHeight() > height - 30) {
if(scrollY > -((mod.customComponentLiteHeight() - 13.5) * 38)) {
scrollY -=12;
}
if(scrollY < -((mod.customComponentLiteHeight() - 15) * 38)) {
scrollY = -((mod.customComponentLiteHeight() - 14.1) * 38);
}
}
break;
case UP:
if(scrollY < -10) {
scrollY +=12;
}else {
if(settingIndex > 13) {
scrollY = 0;
}
if(mod.customComponentLiteHeight() > height - 30) {
scrollY = 0;
}
}
break;
}
}
scrollAnimation.setAnimation((float) scrollY, 16);
// final Scroll scroll = MouseUtils.scroll();
//
// if(scroll != null) {
// switch (scroll) {
// case DOWN:
// if(scrollY > -((settingIndex - 13.5) * 38)) {
// scrollY -=12;
// }
//
// if(settingIndex > 13) {
// if(scrollY < -((settingIndex - 15) * 38)) {
// scrollY = -((settingIndex - 14.1) * 38);
// }
// }
// if(mod.customComponentLiteHeight() > height - 30) {
// if(scrollY > -((mod.customComponentLiteHeight() - 13.5) * 38)) {
// scrollY -=12;
// }
// if(scrollY < -((mod.customComponentLiteHeight() - 15) * 38)) {
// scrollY = -((mod.customComponentLiteHeight() - 14.1) * 38);
// }
// }
// break;
// case UP:
// if(scrollY < -10) {
// scrollY +=12;
// }else {
// if(settingIndex > 13) {
// scrollY = 0;
// }
// if(mod.customComponentLiteHeight() > height - 30) {
// scrollY = 0;
// }
// }
// break;
// }
// }
//
// scrollAnimation.setAnimation((float) scrollY, 16);
if(ClickGUI.close) {
ClickGUI.introAnimation.setDirection(Direction.BACKWARDS);
@ -302,22 +304,22 @@ public class ModSettings extends SilentScreen {
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
super.mouseClicked(mouseX, mouseY, mouseButton);
float scrollY = scrollHelper.getScroll();
int addX = 190;
int addY = 110;
int x = (width / 2) - addX;
int y = (height / 2) - addY;
int width = addX * 2;
int settingY = (int) (y + 25 + scrollAnimation.getValue() + mod.customComponentLiteHeight());
int settingY = (int) (y + 25 + scrollY + mod.customComponentLiteHeight());
String category = "";
if(mod.getCategory() == ModCategory.MODS && MouseUtils.isInside(mouseX, mouseY, x + width - (10 + 8) - 15, y + 5 + scrollAnimation.getValue(), 10, 10)) {
if(mod.getCategory() == ModCategory.MODS && MouseUtils.isInside(mouseX, mouseY, x + width - (10 + 8) - 15, y + 5 + scrollY, 10, 10)) {
Sounds.playButtonSound();
mod.reset(false);
}
if(mod.getCategory() == ModCategory.MODS && Switch.isHovered(mouseX, mouseY, x + width - (10 + 8), y + 6 + scrollAnimation.getValue())) {
if(mod.getCategory() == ModCategory.MODS && Switch.isHovered(mouseX, mouseY, x + width - (10 + 8), y + 6 + scrollY)) {
Sounds.playButtonSound();
mod.toggle();
}

View File

@ -0,0 +1,14 @@
package net.silentclient.client.mixin.accessors.skins;
import net.silentclient.client.mods.render.skins.renderlayers.BodyLayerFeatureRenderer;
import net.silentclient.client.mods.render.skins.renderlayers.HeadLayerFeatureRenderer;
/**
* Used to expose the thinArms setting of the player model
*
*/
public interface PlayerEntityModelAccessor {
public boolean client$hasThinArms();
public HeadLayerFeatureRenderer client$getHeadLayer();
public BodyLayerFeatureRenderer client$getBodyLayer();
}

View File

@ -0,0 +1,15 @@
package net.silentclient.client.mixin.accessors.skins;
import net.silentclient.client.mods.render.skins.render.CustomizableModelPart;
public interface PlayerSettings {
public CustomizableModelPart client$getHeadLayers();
public void client$setupHeadLayers(CustomizableModelPart box);
public CustomizableModelPart[] client$getSkinLayers();
public void client$setupSkinLayers(CustomizableModelPart[] box);
}

View File

@ -0,0 +1,7 @@
package net.silentclient.client.mixin.accessors.skins;
public interface SkullModelAccessor {
public void showHat(boolean val);
}

View File

@ -0,0 +1,11 @@
package net.silentclient.client.mixin.accessors.skins;
import net.silentclient.client.mods.render.skins.render.CustomizableModelPart;
public interface SkullSettings {
public CustomizableModelPart getHeadLayers();
public void setupHeadLayers(CustomizableModelPart box);
}

View File

@ -0,0 +1,47 @@
package net.silentclient.client.mixin.mixins.skins;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import net.silentclient.client.mixin.accessors.skins.PlayerSettings;
import net.silentclient.client.mods.render.skins.render.CustomizableModelPart;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
/**
* Keep player specific settings, data and modifies the eye location when enabled
*
*/
@Mixin(EntityPlayer.class)
public abstract class PlayerMixin extends EntityLivingBase implements PlayerSettings {
public PlayerMixin(World p_i1594_1_) {
super(p_i1594_1_);
}
@Unique
private CustomizableModelPart headLayer;
@Unique
private CustomizableModelPart[] skinLayer;
@Override
public CustomizableModelPart[] client$getSkinLayers() {
return skinLayer;
}
@Override
public void client$setupSkinLayers(CustomizableModelPart[] box) {
this.skinLayer = box;
}
@Override
public CustomizableModelPart client$getHeadLayers() {
return headLayer;
}
@Override
public void client$setupHeadLayers(CustomizableModelPart box) {
this.headLayer = box;
}
}

View File

@ -0,0 +1,177 @@
package net.silentclient.client.mixin.mixins.skins;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelPlayer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.RenderPlayer;
import net.minecraft.client.renderer.entity.RendererLivingEntity;
import net.silentclient.client.Client;
import net.silentclient.client.mixin.accessors.skins.PlayerEntityModelAccessor;
import net.silentclient.client.mixin.accessors.skins.PlayerSettings;
import net.silentclient.client.mods.render.skins.SkinUtil;
import net.silentclient.client.mods.render.skins.SkinsMod;
import net.silentclient.client.mods.render.skins.renderlayers.BodyLayerFeatureRenderer;
import net.silentclient.client.mods.render.skins.renderlayers.HeadLayerFeatureRenderer;
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;
@Mixin(RenderPlayer.class)
public abstract class PlayerRendererMixin extends RendererLivingEntity<AbstractClientPlayer> implements PlayerEntityModelAccessor {
@Shadow
private boolean smallArms;
@Unique
private HeadLayerFeatureRenderer client$headLayer;
@Unique
private BodyLayerFeatureRenderer client$bodyLayer;
public PlayerRendererMixin(RenderManager p_i46156_1_, ModelBase p_i46156_2_, float p_i46156_3_) {
super(p_i46156_1_, p_i46156_2_, p_i46156_3_);
}
@Inject(method = "<init>*", at = @At("RETURN"))
public void onCreate(CallbackInfo info) {
client$headLayer = new HeadLayerFeatureRenderer((RenderPlayer)(Object)this);
client$bodyLayer = new BodyLayerFeatureRenderer((RenderPlayer)(Object)this);
}
@Inject(method = "setModelVisibilities", at = @At("HEAD"))
private void setModelProperties(AbstractClientPlayer abstractClientPlayer, CallbackInfo info) {
ModelPlayer playerModel = getMainModel();
if(!Client.getInstance().getModInstances().getModByClass(SkinsMod.class).isEnabled()) {
playerModel.bipedHeadwear.isHidden = false;
playerModel.bipedBodyWear.isHidden = false;
playerModel.bipedLeftArmwear.isHidden = false;
playerModel.bipedRightArmwear.isHidden = false;
playerModel.bipedLeftLegwear.isHidden = false;
playerModel.bipedRightLegwear.isHidden = false;
return;
}
if(Minecraft.getMinecraft().thePlayer.getPositionVector().squareDistanceTo(abstractClientPlayer.getPositionVector()) < Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Level Of Detail Distance").getValInt()*Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Level Of Detail Distance").getValInt()) {
playerModel.bipedHeadwear.isHidden = playerModel.bipedHeadwear.isHidden || Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Hat").getValBoolean();
playerModel.bipedBodyWear.isHidden = playerModel.bipedBodyWear.isHidden || Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Jacket").getValBoolean();
playerModel.bipedLeftArmwear.isHidden = playerModel.bipedLeftArmwear.isHidden || Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Left Sleeve").getValBoolean();
playerModel.bipedRightArmwear.isHidden = playerModel.bipedRightArmwear.isHidden || Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Right Sleeve").getValBoolean();
playerModel.bipedLeftLegwear.isHidden = playerModel.bipedLeftLegwear.isHidden || Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Left Pants").getValBoolean();
playerModel.bipedRightLegwear.isHidden = playerModel.bipedRightLegwear.isHidden || Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Right Pants").getValBoolean();
} else {
// not correct, but the correct way doesn't work cause 1.8 or whatever
if(!abstractClientPlayer.isSpectator()) {
playerModel.bipedHeadwear.isHidden = false;
playerModel.bipedBodyWear.isHidden = false;
playerModel.bipedLeftArmwear.isHidden = false;
playerModel.bipedRightArmwear.isHidden = false;
playerModel.bipedLeftLegwear.isHidden = false;
playerModel.bipedRightLegwear.isHidden = false;
}
}
}
@Override
public HeadLayerFeatureRenderer client$getHeadLayer() {
return client$headLayer;
}
@Override
public BodyLayerFeatureRenderer client$getBodyLayer() {
return client$bodyLayer;
}
@Override
public boolean client$hasThinArms() {
return smallArms;
}
@Shadow
public abstract ModelPlayer getMainModel();
@Inject(method = "renderRightArm", at = @At("RETURN"))
public void renderRightArm(AbstractClientPlayer player, CallbackInfo info) {
if(!Client.getInstance().getModInstances().getModByClass(SkinsMod.class).isEnabled()) {
return;
}
client$renderFirstPersonArm(player, 3);
}
@Inject(method = "renderLeftArm", at = @At("RETURN"))
public void renderLeftArm(AbstractClientPlayer player, CallbackInfo info) {
if(!Client.getInstance().getModInstances().getModByClass(SkinsMod.class).isEnabled()) {
return;
}
client$renderFirstPersonArm(player, 2);
}
@Unique
private void client$renderFirstPersonArm(AbstractClientPlayer player, int layerId) {
ModelPlayer modelplayer = getMainModel();
float pixelScaling = Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Voxel Size").getValFloat();
PlayerSettings settings = (PlayerSettings) player;
if(settings.client$getSkinLayers() == null && !client$setupModel(player, settings)) {
return;
}
GlStateManager.pushMatrix();
modelplayer.bipedRightArm.postRender(0.0625F);
GlStateManager.scale(0.0625, 0.0625, 0.0625);
GlStateManager.scale(pixelScaling, pixelScaling, pixelScaling);
if(!smallArms) {
settings.client$getSkinLayers()[layerId].x = -0.998f*16f;
} else {
settings.client$getSkinLayers()[layerId].x = -0.499f*16;
}
settings.client$getSkinLayers()[layerId].render(false);
GlStateManager.popMatrix();
}
@Unique
private boolean client$setupModel(AbstractClientPlayer abstractClientPlayerEntity, PlayerSettings settings) {
if(!SkinUtil.hasCustomSkin(abstractClientPlayerEntity)) {
return false; // default skin
}
SkinUtil.setup3dLayers(abstractClientPlayerEntity, settings, smallArms, null);
return true;
}
// @Inject(method = "renderHand", at = @At("RETURN"))
// private void renderHand(PoseStack poseStack, MultiBufferSource multiBufferSource, int i,
// AbstractClientPlayer abstractClientPlayer, ModelPart arm, ModelPart sleeve, CallbackInfo info) {
// if(sleeve.visible)return; // Vanilla one is active
// PlayerSettings settings = (PlayerSettings) abstractClientPlayer;
// float pixelScaling = 1.1f;
// float armHeightScaling = 1.1f;
// boolean thinArms = ((PlayerEntityModelAccessor)getModel()).hasThinArms();
// if(settings.getSkinLayers() == null && !SkinUtil.setup3dLayers(abstractClientPlayer, settings, thinArms, getModel())) {
// return;
// }
// CustomizableModelPart part = null;
// if(sleeve == this.model.leftSleeve) {
// part = settings.getSkinLayers()[2];
// }else {
// part = settings.getSkinLayers()[3];
// }
// part.copyFrom(arm);
// poseStack.pushPose();
// poseStack.scale(pixelScaling, armHeightScaling, pixelScaling);
// part.y -= 0.6;
// if(!thinArms) {
// part.x -= 0.4;
// }
// part.render(poseStack,
// multiBufferSource
// .getBuffer(RenderType.entityTranslucent(abstractClientPlayer.getSkinTextureLocation())),
// i, OverlayTexture.NO_OVERLAY);
// part.setPos(0, 0, 0);
// part.setRotation(0, 0, 0);
// poseStack.popPose();
//
// }
}

View File

@ -0,0 +1,52 @@
package net.silentclient.client.mixin.mixins.skins;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RendererLivingEntity;
import net.minecraft.entity.EntityLivingBase;
import net.silentclient.client.Client;
import net.silentclient.client.mixin.accessors.skins.PlayerEntityModelAccessor;
import net.silentclient.client.mods.render.skins.SkinsMod;
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;
@Mixin(RendererLivingEntity.class)
public class RendererLivingEntityMixin<T extends EntityLivingBase> {
@Inject(method = "renderModel", at = @At("TAIL"))
protected void renderModelLayers(T p_renderModel_1_, float p_renderModel_2_, float p_renderModel_3_,
float p_renderModel_4_, float p_renderModel_5_, float p_renderModel_6_, float p_renderModel_7_, CallbackInfo info) {
if(!Client.getInstance().getModInstances().getModByClass(SkinsMod.class).isEnabled()) {
return;
}
if(!(this instanceof PlayerEntityModelAccessor)) {
return;
}
boolean flag = !p_renderModel_1_.isInvisible();
boolean flag1 = (!flag && !p_renderModel_1_.isInvisibleToPlayer((Minecraft.getMinecraft()).thePlayer));
if (flag || flag1) {
PlayerEntityModelAccessor playerRenderer = (PlayerEntityModelAccessor) this;
if (flag1) {
GlStateManager.pushMatrix();
GlStateManager.color(1.0F, 1.0F, 1.0F, 0.15F);
GlStateManager.depthMask(false);
GlStateManager.enableBlend();
GlStateManager.blendFunc(770, 771);
GlStateManager.alphaFunc(516, 0.003921569F);
}
playerRenderer.client$getHeadLayer().doRenderLayer((AbstractClientPlayer) p_renderModel_1_, p_renderModel_2_, 0f, p_renderModel_3_, p_renderModel_4_, p_renderModel_5_, p_renderModel_6_, p_renderModel_7_);
playerRenderer.client$getBodyLayer().doRenderLayer((AbstractClientPlayer) p_renderModel_1_, p_renderModel_2_, 0f, p_renderModel_3_, p_renderModel_4_, p_renderModel_5_, p_renderModel_6_, p_renderModel_7_);
if (flag1) {
GlStateManager.disableBlend();
GlStateManager.alphaFunc(516, 0.1F);
GlStateManager.popMatrix();
GlStateManager.depthMask(true);
}
}
}
}

View File

@ -11,6 +11,7 @@ import net.silentclient.client.mods.hypixel.togglechat.ToggleChatMod;
import net.silentclient.client.mods.player.*;
import net.silentclient.client.mods.render.*;
import net.silentclient.client.mods.render.crosshair.CrosshairMod;
import net.silentclient.client.mods.render.skins.SkinsMod;
import net.silentclient.client.mods.settings.CosmeticsMod;
import net.silentclient.client.mods.settings.FPSBoostMod;
import net.silentclient.client.mods.settings.GeneralMod;
@ -189,6 +190,7 @@ public class ModInstances {
}
mods.add(new QuickPlayMod());
mods.add(new SoundsMod());
mods.add(new SkinsMod());
}
public void postInit() {

View File

@ -1,10 +0,0 @@
package net.silentclient.client.mods.render;
import net.silentclient.client.mods.Mod;
import net.silentclient.client.mods.ModCategory;
public class SkinsMod extends Mod {
public SkinsMod() {
super("3D Skins", ModCategory.MODS, "silentclient/icons/mods/3dskins.png");
}
}

View File

@ -0,0 +1,33 @@
package net.silentclient.client.mods.render.skins;
import org.lwjgl.util.vector.Vector3f;
import net.minecraft.util.Vec3i;
public enum Direction {
DOWN(new Vec3i(0, -1, 0)), UP(new Vec3i(0, 1, 0)), NORTH(new Vec3i(0, 0, -1)), SOUTH(new Vec3i(0, 0, 1)),
WEST(new Vec3i(-1, 0, 0)), EAST(new Vec3i(1, 0, 0));
private Direction(Vec3i normal) {
this.normal = normal;
}
private final Vec3i normal;
public int getStepX() {
return this.normal.getX();
}
public int getStepY() {
return this.normal.getY();
}
public int getStepZ() {
return this.normal.getZ();
}
public Vector3f step() {
return new Vector3f(getStepX(), getStepY(), getStepZ());
}
}

View File

@ -0,0 +1,79 @@
package net.silentclient.client.mods.render.skins;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.client.model.ModelPlayer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.ITextureObject;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.DefaultPlayerSkin;
import net.minecraft.util.ResourceLocation;
import net.silentclient.client.mixin.accessors.skins.PlayerSettings;
import net.silentclient.client.mixin.accessors.skins.SkullSettings;
import net.silentclient.client.mods.render.skins.opengl.NativeImage;
import net.silentclient.client.mods.render.skins.render.CustomizableModelPart;
import net.silentclient.client.mods.render.skins.render.SolidPixelWrapper;
public class SkinUtil {
public static boolean hasCustomSkin(AbstractClientPlayer player) {
return !DefaultPlayerSkin.getDefaultSkin((player).getUniqueID()).equals((player).getLocationSkin());
}
private static NativeImage getSkinTexture(AbstractClientPlayer player) {
return getTexture(player.getLocationSkin());
}
private static NativeImage getTexture(ResourceLocation resource) {
NativeImage skin = new NativeImage(64, 64, false);
TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
ITextureObject abstractTexture = textureManager.getTexture(resource);
if(abstractTexture == null)return null; // fail save
GlStateManager.bindTexture(abstractTexture.getGlTextureId());
skin.downloadTexture(0, false);
return skin;
}
public static boolean setup3dLayers(AbstractClientPlayer abstractClientPlayerEntity, PlayerSettings settings, boolean thinArms, ModelPlayer model) {
if(!SkinUtil.hasCustomSkin(abstractClientPlayerEntity)) {
return false; // default skin
}
NativeImage skin = SkinUtil.getSkinTexture(abstractClientPlayerEntity);
if(skin == null)return false; // fail save
CustomizableModelPart[] layers = new CustomizableModelPart[5];
layers[0] = SolidPixelWrapper.wrapBox(skin, 4, 12, 4, 0, 48, true, 0f);
layers[1] = SolidPixelWrapper.wrapBox(skin, 4, 12, 4, 0, 32, true, 0f);
if(thinArms) {
layers[2] = SolidPixelWrapper.wrapBox(skin, 3, 12, 4, 48, 48, true, -2.5f);
layers[3] = SolidPixelWrapper.wrapBox(skin, 3, 12, 4, 40, 32, true, -2.5f);
} else {
layers[2] = SolidPixelWrapper.wrapBox(skin, 4, 12, 4, 48, 48, true, -2.5f);
layers[3] = SolidPixelWrapper.wrapBox(skin, 4, 12, 4, 40, 32, true, -2.5f);
}
layers[4] = SolidPixelWrapper.wrapBox(skin, 8, 12, 4, 16, 32, true, -0.8f);
settings.client$setupSkinLayers(layers);
settings.client$setupHeadLayers(SolidPixelWrapper.wrapBox(skin, 8, 8, 8, 32, 0, false, 0.6f));
skin.close();
return true;
}
public static boolean setup3dLayers(GameProfile gameprofile, SkullSettings settings) {
if(gameprofile == null) {
return false; // no gameprofile
}
/*Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = Minecraft.getMinecraft().getSkinManager()
.loadProfileTextures(gameprofile);
MinecraftProfileTexture texture = map.get(MinecraftProfileTexture.Type.SKIN);
if(texture == null) {
return false; // it's a gameprofile, but no skin.
}
NativeImage skin = SkinUtil.getTexture(Minecraft.getMinecraft().getSkinManager()
.registerTexture(texture, MinecraftProfileTexture.Type.SKIN));
settings.setupHeadLayers(SolidPixelWrapper.wrapBox(skin, 8, 8, 8, 32, 0, false, 0.6f));
skin.close();
return true;*/
return false;
}
}

View File

@ -0,0 +1,34 @@
package net.silentclient.client.mods.render.skins;
import net.silentclient.client.mods.Mod;
import net.silentclient.client.mods.ModCategory;
public class SkinsMod extends Mod {
public SkinsMod() {
super("3D Skins", ModCategory.MODS, "silentclient/icons/mods/skinsmod.png");
}
@Override
public void setup() {
super.setup();
setNewMod(true);
this.addBooleanSetting("3D Hat", this, true);
this.addBooleanSetting("3D Jacket", this, true);
this.addBooleanSetting("3D Left Sleeve", this, true);
this.addBooleanSetting("3D Right Sleeve", this, true);
this.addBooleanSetting("3D Left Pants", this, true);
this.addBooleanSetting("3D Right Pants", this, true);
this.addSliderSetting("Voxel Size", this, 1.15F, 1F, 1.4F, false);
this.addSliderSetting("Head Voxel Size", this, 1.18F, 1F, 1.25F, false);
this.addSliderSetting("Body Voxel Width Size", this, 1.05F, 1F, 1.4F, false);
this.addBooleanSetting("3D Skulls", this, true);
this.addBooleanSetting("3D Skull Items", this, true);
this.addSliderSetting("Skull Voxel Size", this, 1.1F, 1F, 1.2F, false);
this.addSliderSetting("Level Of Detail Distance", this, 14, 5, 40, true);
this.addBooleanSetting("Fast Render", this, true);
}
}

View File

@ -0,0 +1,31 @@
package net.silentclient.client.mods.render.skins;
import net.minecraft.item.ItemStack;
import net.silentclient.client.mixin.accessors.skins.SkullSettings;
import net.silentclient.client.mods.render.skins.render.CustomizableModelPart;
import java.util.WeakHashMap;
public class SkullRendererCache {
public static boolean renderNext = false;
public static SkullSettings lastSkull = null;
public static WeakHashMap<ItemStack, SkullSettings> itemCache = new WeakHashMap<>();
public static class ItemSettings implements SkullSettings {
private CustomizableModelPart hatModel = null;
@Override
public CustomizableModelPart getHeadLayers() {
return hatModel;
}
@Override
public void setupHeadLayers(CustomizableModelPart box) {
this.hatModel = box;
}
}
}

View File

@ -0,0 +1,15 @@
package net.silentclient.client.mods.render.skins.opengl;
import org.lwjgl.opengl.GL11;
import java.nio.ByteBuffer;
public class GlStateManager {
public static void _getTexImage(int i, int j, int k, int l, ByteBuffer m) {
GL11.glGetTexImage(i, j, k, l, m);
}
public static void _pixelStore(int i, int j) {
GL11.glPixelStorei(i, j);
}
}

View File

@ -0,0 +1,294 @@
package net.silentclient.client.mods.render.skins.opengl;
import java.nio.ByteBuffer;
public final class NativeImage implements AutoCloseable {
private final Format format;
private final int width;
private final int height;
private ByteBuffer buffer;
private final int size;
public NativeImage(int i, int j, boolean bl) {
this(Format.RGBA, i, j, bl);
}
public NativeImage(Format format, int i, int j, boolean bl) {
if (i <= 0 || j <= 0)
throw new IllegalArgumentException("Invalid texture size: " + i + "x" + j);
this.format = format;
this.width = i;
this.height = j;
this.size = i * j * format.components();
buffer = ByteBuffer.allocateDirect(this.size);
}
private boolean isOutsideBounds(int i, int j) {
return (i < 0 || i >= this.width || j < 0 || j >= this.height);
}
public void close() {
// nothing to do?
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
public Format format() {
return this.format;
}
public int getPixelRGBA(int i, int j) {
if (this.format != Format.RGBA)
throw new IllegalArgumentException(
String.format("getPixelRGBA only works on RGBA images; have %s", new Object[]{this.format}));
if (isOutsideBounds(i, j))
throw new IllegalArgumentException(
String.format("(%s, %s) outside of image bounds (%s, %s)", new Object[]{Integer.valueOf(i),
Integer.valueOf(j), Integer.valueOf(this.width), Integer.valueOf(this.height)}));
int l = (i + j * this.width) * 4;
return buffer.getInt(l);
}
public void setPixelRGBA(int i, int j, int k) {
if (this.format != Format.RGBA)
throw new IllegalArgumentException(
String.format("getPixelRGBA only works on RGBA images; have %s", new Object[]{this.format}));
if (isOutsideBounds(i, j))
throw new IllegalArgumentException(
String.format("(%s, %s) outside of image bounds (%s, %s)", new Object[]{Integer.valueOf(i),
Integer.valueOf(j), Integer.valueOf(this.width), Integer.valueOf(this.height)}));
int l = (i + j * this.width) * 4;
buffer.putInt(l, k);
}
public byte getLuminanceOrAlpha(int i, int j) {
if (!this.format.hasLuminanceOrAlpha())
throw new IllegalArgumentException(String.format("no luminance or alpha in %s", new Object[]{this.format}));
if (isOutsideBounds(i, j))
throw new IllegalArgumentException(
String.format("(%s, %s) outside of image bounds (%s, %s)", new Object[]{Integer.valueOf(i),
Integer.valueOf(j), Integer.valueOf(this.width), Integer.valueOf(this.height)}));
int k = (i + j * this.width) * this.format.components() + this.format.luminanceOrAlphaOffset() / 8;
return buffer.get(k);
}
public void downloadTexture(int i, boolean bl) {
//RenderSystem.assertOnRenderThread();
this.format.setPackPixelStoreState();
GlStateManager._getTexImage(3553, i, this.format.glFormat(), 5121, this.buffer);
if (bl && this.format.hasAlpha())
for (int j = 0; j < getHeight(); j++) {
for (int k = 0; k < getWidth(); k++)
setPixelRGBA(k, j, getPixelRGBA(k, j) | 255 << this.format.alphaOffset());
}
}
// public void downloadDepthBuffer(float f) {
// //RenderSystem.assertOnRenderThread();
// if (this.format.components() != 1)
// throw new IllegalStateException("Depth buffer must be stored in NativeImage with 1 component.");
// checkAllocated();
// this.format.setPackPixelStoreState();
// GlStateManager._readPixels(0, 0, this.width, this.height, 6402, 5121, this.pixels);
// }
public static int getA(int i) {
return i >> 24 & 0xFF;
}
public static int getR(int i) {
return i >> 0 & 0xFF;
}
public static int getG(int i) {
return i >> 8 & 0xFF;
}
public static int getB(int i) {
return i >> 16 & 0xFF;
}
public static int combine(int i, int j, int k, int l) {
return (i & 0xFF) << 24 | (j & 0xFF) << 16 | (k & 0xFF) << 8 | (l & 0xFF) << 0;
}
public enum InternalGlFormat {
RGBA(6408), RGB(6407), RG(33319), RED(6403);
private final int glFormat;
InternalGlFormat(int j) {
this.glFormat = j;
}
public int glFormat() {
return this.glFormat;
}
}
public enum Format {
RGBA(4, 6408, true, true, true, false, true, 0, 8, 16, 255, 24, true), RGB(3, 6407, true, true, true, false,
false, 0, 8, 16, 255, 255, true), LUMINANCE_ALPHA(2, 33319, false, false, false, true, true, 255, 255,
255, 0, 8, true), LUMINANCE(1, 6403, false, false, false, true, false, 0, 0, 0, 0, 255, true);
final int components;
private final int glFormat;
private final boolean hasRed;
private final boolean hasGreen;
private final boolean hasBlue;
private final boolean hasLuminance;
private final boolean hasAlpha;
private final int redOffset;
private final int greenOffset;
private final int blueOffset;
private final int luminanceOffset;
private final int alphaOffset;
private final boolean supportedByStb;
Format(int j, int k, boolean bl, boolean bl2, boolean bl3, boolean bl4, boolean bl5, int l, int m, int n, int o,
int p, boolean bl6) {
this.components = j;
this.glFormat = k;
this.hasRed = bl;
this.hasGreen = bl2;
this.hasBlue = bl3;
this.hasLuminance = bl4;
this.hasAlpha = bl5;
this.redOffset = l;
this.greenOffset = m;
this.blueOffset = n;
this.luminanceOffset = o;
this.alphaOffset = p;
this.supportedByStb = bl6;
}
public int components() {
return this.components;
}
public void setPackPixelStoreState() {
//RenderSystem.assertOnRenderThread();
GlStateManager._pixelStore(3333, components());
}
public void setUnpackPixelStoreState() {
GlStateManager._pixelStore(3317, components());
}
public int glFormat() {
return this.glFormat;
}
public boolean hasRed() {
return this.hasRed;
}
public boolean hasGreen() {
return this.hasGreen;
}
public boolean hasBlue() {
return this.hasBlue;
}
public boolean hasLuminance() {
return this.hasLuminance;
}
public boolean hasAlpha() {
return this.hasAlpha;
}
public int redOffset() {
return this.redOffset;
}
public int greenOffset() {
return this.greenOffset;
}
public int blueOffset() {
return this.blueOffset;
}
public int luminanceOffset() {
return this.luminanceOffset;
}
public int alphaOffset() {
return this.alphaOffset;
}
public boolean hasLuminanceOrRed() {
return (this.hasLuminance || this.hasRed);
}
public boolean hasLuminanceOrGreen() {
return (this.hasLuminance || this.hasGreen);
}
public boolean hasLuminanceOrBlue() {
return (this.hasLuminance || this.hasBlue);
}
public boolean hasLuminanceOrAlpha() {
return (this.hasLuminance || this.hasAlpha);
}
public int luminanceOrRedOffset() {
return this.hasLuminance ? this.luminanceOffset : this.redOffset;
}
public int luminanceOrGreenOffset() {
return this.hasLuminance ? this.luminanceOffset : this.greenOffset;
}
public int luminanceOrBlueOffset() {
return this.hasLuminance ? this.luminanceOffset : this.blueOffset;
}
public int luminanceOrAlphaOffset() {
return this.hasLuminance ? this.luminanceOffset : this.alphaOffset;
}
public boolean supportedByStb() {
return this.supportedByStb;
}
static Format getStbFormat(int i) {
switch (i) {
case 1 :
return LUMINANCE;
case 2 :
return LUMINANCE_ALPHA;
case 3 :
return RGB;
}
return RGBA;
}
}
}

View File

@ -0,0 +1,152 @@
package net.silentclient.client.mods.render.skins.render;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.silentclient.client.mods.render.skins.Direction;
import org.lwjgl.util.vector.Vector3f;
public class CustomizableCube {
private final Direction[] hidden;
private final Polygon[] polygons;
private int polygonCount = 0;
public final float minX;
public final float minY;
public final float minZ;
public final float maxX;
public final float maxY;
public final float maxZ;
public CustomizableCube(int u, int v, float x, float y, float z, float sizeX, float sizeY, float sizeZ, float extraX, float extraY,
float extraZ, boolean mirror, float textureWidth, float textureHeight, Direction[] hide) {
this.hidden = hide;
this.minX = x;
this.minY = y;
this.minZ = z;
this.maxX = x + sizeX;
this.maxY = y + sizeY;
this.maxZ = z + sizeZ;
this.polygons = new Polygon[6];
float pX = x + sizeX;
float pY = y + sizeY;
float pZ = z + sizeZ;
x -= extraX;
y -= extraY;
z -= extraZ;
pX += extraX;
pY += extraY;
pZ += extraZ;
if (mirror) {
float i = pX;
pX = x;
x = i;
}
Vertex vertex = new Vertex(x, y, z, 0.0F, 0.0F);
Vertex vertex2 = new Vertex(pX, y, z, 0.0F, 8.0F);
Vertex vertex3 = new Vertex(pX, pY, z, 8.0F, 8.0F);
Vertex vertex4 = new Vertex(x, pY, z, 8.0F, 0.0F);
Vertex vertex5 = new Vertex(x, y, pZ, 0.0F, 0.0F);
Vertex vertex6 = new Vertex(pX, y, pZ, 0.0F, 8.0F);
Vertex vertex7 = new Vertex(pX, pY, pZ, 8.0F, 8.0F);
Vertex vertex8 = new Vertex(x, pY, pZ, 8.0F, 0.0F);
float l = u + sizeZ + sizeX;
float n = u + sizeZ + sizeX + sizeZ;
float q = v + sizeZ;
float r = v + sizeZ + sizeY;
if(visibleFace(Direction.DOWN))
this.polygons[polygonCount++] = new Polygon(new Vertex[]{vertex6, vertex5, vertex, vertex2}, l, q, n, r, textureWidth, textureHeight, mirror, Direction.DOWN);
if(visibleFace(Direction.UP))
this.polygons[polygonCount++] = new Polygon(new Vertex[]{vertex3, vertex4, vertex8, vertex7}, l, q, n, r, textureWidth, textureHeight, mirror, Direction.UP);
if(visibleFace(Direction.WEST))
this.polygons[polygonCount++] = new Polygon(new Vertex[]{vertex, vertex5, vertex8, vertex4}, l, q, n, r, textureWidth, textureHeight, mirror, Direction.WEST);
if(visibleFace(Direction.NORTH))
this.polygons[polygonCount++] = new Polygon(new Vertex[]{vertex2, vertex, vertex4, vertex3}, l, q, n, r, textureWidth, textureHeight, mirror, Direction.NORTH);
if(visibleFace(Direction.EAST))
this.polygons[polygonCount++] = new Polygon(new Vertex[]{vertex6, vertex2, vertex3, vertex7}, l, q, n, r, textureWidth, textureHeight, mirror, Direction.EAST);
if(visibleFace(Direction.SOUTH))
this.polygons[polygonCount++] = new Polygon(new Vertex[]{vertex5, vertex6, vertex7, vertex8}, l, q, n, r, textureWidth, textureHeight, mirror, Direction.SOUTH);
}
private boolean visibleFace(Direction face) {
for(Direction dir : hidden) {
if(dir == face)return false;
}
return true;
}
public void render(WorldRenderer worldRenderer, boolean redTint) {
redTint = false;
worldRenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR_NORMAL);
Polygon polygon;
for (int id = 0; id < polygonCount; id++) {
polygon = polygons[id];
for (int i = 0; i < 4; i++) {
Vertex vertex = polygon.vertices[i];
worldRenderer
.pos(vertex.pos.x, vertex.pos.y,
vertex.pos.z)
.tex(vertex.u, vertex.v).color(255, redTint ? 127 : 255, redTint ? 127 : 255, 255).normal(polygon.normal.x, polygon.normal.y, polygon.normal.z)
.endVertex();
}
}
Tessellator.getInstance().draw();
}
private static class Polygon {
public final Vertex[] vertices;
public final Vector3f normal;
public Polygon(Vertex[] vertexs, float f, float g, float h, float i, float j, float k, boolean bl,
Direction dir) {
this.vertices = vertexs;
float l = 0.0F / j;
float m = 0.0F / k;
vertexs[0] = vertexs[0].remap(h / j - l, g / k + m);
vertexs[1] = vertexs[1].remap(f / j + l, g / k + m);
vertexs[2] = vertexs[2].remap(f / j + l, i / k - m);
vertexs[3] = vertexs[3].remap(h / j - l, i / k - m);
if (bl) {
int n = vertexs.length;
for (int o = 0; o < n / 2; o++) {
Vertex vertex = vertexs[o];
vertexs[o] = vertexs[n - 1 - o];
vertexs[n - 1 - o] = vertex;
}
}
this.normal = dir.step();
if (bl)
this.normal.setX(this.normal.getX()*-1);
}
}
private static class Vertex {
public final Vector3f pos;
public final float u;
public final float v;
public final float o,p,q;
public Vertex(float f, float g, float h, float i, float j) {
this(new Vector3f(f, g, h), i, j);
}
public Vertex remap(float f, float g) {
return new Vertex(this.pos, f, g);
}
public Vertex(Vector3f vector3f, float f, float g) {
this.pos = vector3f;
this.u = f;
this.v = g;
o = pos.x / 16.0F;
p = pos.y / 16.0F;
q = pos.z / 16.0F;
}
}
}

View File

@ -0,0 +1,41 @@
package net.silentclient.client.mods.render.skins.render;
import com.google.common.collect.Lists;
import net.silentclient.client.mods.render.skins.Direction;
import java.util.List;
public class CustomizableCubeListBuilder {
private final List<CustomizableCube> cubes = Lists.newArrayList();
private int xTexOffs;
private int yTexOffs;
private boolean mirror;
public static CustomizableCubeListBuilder create() {
return new CustomizableCubeListBuilder();
}
public CustomizableCubeListBuilder texOffs(int i, int j) {
this.xTexOffs = i;
this.yTexOffs = j;
return this;
}
public CustomizableCubeListBuilder mirror(boolean bl) {
this.mirror = bl;
return this;
}
public List<CustomizableCube> getCubes() {
return cubes;
}
public CustomizableCubeListBuilder addBox(float x, float y, float z, float pixelSize, Direction[] hide) {
int textureSize = 64;
this.cubes.add(new CustomizableCube(xTexOffs, yTexOffs, x, y, z, pixelSize, pixelSize, pixelSize, 0, 0, 0,
this.mirror, textureSize, textureSize, hide));
return this;
}
}

View File

@ -0,0 +1,57 @@
package net.silentclient.client.mods.render.skins.render;
import net.minecraft.client.model.ModelBox;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import java.util.List;
/**
* Cut down copy of the Vanilla ModelPart to bypass Optifine/Sodium screwing
* with the CustomizableCube class
*
*/
public class CustomizableModelPart {
public float x;
public float y;
public float z;
public boolean visible = true;
private final List<CustomizableCube> cubes;
public CustomizableModelPart(List<CustomizableCube> list) {
this.cubes = list;
}
public void copyFrom(ModelBox modelPart) {
this.x = modelPart.posX1;
this.y = modelPart.posY1;
this.z = modelPart.posZ1;
}
public void setPos(float f, float g, float h) {
this.x = f;
this.y = g;
this.z = h;
}
public void render(boolean redTint) {
if (!this.visible)
return;
GlStateManager.pushMatrix();
translateAndRotate();
compile(redTint);
GlStateManager.popMatrix();
}
public void translateAndRotate() {
GlStateManager.translate((this.x / 16.0F), (this.y / 16.0F), (this.z / 16.0F));
}
private void compile(boolean redTint) {
for (CustomizableCube cube : this.cubes)
cube.render(Tessellator.getInstance().getWorldRenderer(), redTint);
}
}

View File

@ -0,0 +1,108 @@
package net.silentclient.client.mods.render.skins.render;
import net.silentclient.client.mods.render.skins.Direction;
import net.silentclient.client.mods.render.skins.opengl.NativeImage;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class SolidPixelWrapper {
public static CustomizableModelPart wrapBox(NativeImage natImage, int width,
int height, int depth, int textureU, int textureV, boolean topPivot, float rotationOffset) {
List<CustomizableCube> cubes = new ArrayList<>();
float pixelSize = 1f;
float staticXOffset = -width / 2f;
float staticYOffset = topPivot ? +rotationOffset : -height + rotationOffset;
float staticZOffset = -depth / 2f;
// Front/back
for (int u = 0; u < width; u++) {
for (int v = 0; v < height; v++) {
// front
addPixel(natImage, cubes, pixelSize, u == 0 || v == 0 || u == width - 1 || v == height - 1,
textureU + depth + u, textureV + depth + v, staticXOffset + u, staticYOffset + v, staticZOffset,
Direction.SOUTH);
// back
addPixel(natImage, cubes, pixelSize, u == 0 || v == 0 || u == width - 1 || v == height - 1,
textureU + 2 * depth + width + u, textureV + depth + v, staticXOffset + width - 1 - u,
staticYOffset + v, staticZOffset + depth - 1, Direction.NORTH);
}
}
// sides
for (int u = 0; u < depth; u++) {
for (int v = 0; v < height; v++) {
// left
addPixel(natImage, cubes, pixelSize, u == 0 || v == 0 || u == depth - 1 || v == height - 1,
textureU - 1 + depth - u, textureV + depth + v, staticXOffset, staticYOffset + v,
staticZOffset + u, Direction.EAST);
// right
addPixel(natImage, cubes, pixelSize, u == 0 || v == 0 || u == depth - 1 || v == height - 1,
textureU + depth + width + u, textureV + depth + v, staticXOffset + width - 1f,
staticYOffset + v, staticZOffset + u, Direction.WEST);
}
}
// top/bottom
for (int u = 0; u < width; u++) {
for (int v = 0; v < depth; v++) {
// top
addPixel(natImage, cubes, pixelSize, u == 0 || v == 0 || u == width - 1 || v == depth - 1,
textureU + depth + u, textureV + depth - 1 - v, staticXOffset + u, staticYOffset,
staticZOffset + v, Direction.UP); // Sides are flipped cause ?!?
// bottom
addPixel(natImage, cubes, pixelSize, u == 0 || v == 0 || u == width - 1 || v == depth - 1,
textureU + depth + width + u, textureV + depth - 1 - v, staticXOffset + u,
staticYOffset + height - 1f, staticZOffset + v, Direction.DOWN); // Sides are flipped cause ?!?
}
}
return new CustomizableModelPart(cubes);
}
private static int[][] offsets = new int[][] { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
private static Direction[] hiddenDirN = new Direction[] { Direction.WEST, Direction.EAST, Direction.UP,
Direction.DOWN };
private static Direction[] hiddenDirS = new Direction[] { Direction.EAST, Direction.WEST, Direction.UP,
Direction.DOWN };
private static Direction[] hiddenDirW = new Direction[] { Direction.SOUTH, Direction.NORTH, Direction.UP,
Direction.DOWN };
private static Direction[] hiddenDirE = new Direction[] { Direction.NORTH, Direction.SOUTH, Direction.UP,
Direction.DOWN };
private static Direction[] hiddenDirUD = new Direction[] { Direction.EAST, Direction.WEST, Direction.NORTH,
Direction.SOUTH };
private static void addPixel(NativeImage natImage, List<CustomizableCube> cubes, float pixelSize, boolean onBorder, int u,
int v, float x, float y, float z, Direction dir) {
if (natImage.getLuminanceOrAlpha(u, v) != 0) {
Set<Direction> hide = new HashSet<>();
if (!onBorder) {
for (int i = 0; i < offsets.length; i++) {
int tU = u + offsets[i][1];
int tV = v + offsets[i][0];
if (tU >= 0 && tU < 64 && tV >= 0 && tV < 64 && natImage.getLuminanceOrAlpha(tU, tV) != 0) {
if (dir == Direction.NORTH)
hide.add(hiddenDirN[i]);
if (dir == Direction.SOUTH)
hide.add(hiddenDirS[i]);
if (dir == Direction.EAST)
hide.add(hiddenDirE[i]);
if (dir == Direction.WEST)
hide.add(hiddenDirW[i]);
if (dir == Direction.UP || dir == Direction.DOWN)
hide.add(hiddenDirUD[i]);
}
}
hide.add(dir);
}
cubes.addAll(CustomizableCubeListBuilder.create().texOffs(u - 2, v - 1)
.addBox(x, y, z, pixelSize, hide.toArray(new Direction[hide.size()])).getCubes());
// wrapper.setTextureOffset(u-2, v-1);
// wrapper.addCustomCuboid(x, y, z, pixelSize, pixelSize, pixelSize,
// hide.toArray(new Direction[hide.size()]));
}
}
}

View File

@ -0,0 +1,146 @@
package net.silentclient.client.mods.render.skins.renderlayers;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderPlayer;
import net.minecraft.client.renderer.entity.layers.LayerRenderer;
import net.minecraft.entity.player.EnumPlayerModelParts;
import net.silentclient.client.Client;
import net.silentclient.client.mixin.accessors.skins.PlayerEntityModelAccessor;
import net.silentclient.client.mixin.accessors.skins.PlayerSettings;
import net.silentclient.client.mods.render.skins.SkinUtil;
import net.silentclient.client.mods.render.skins.SkinsMod;
import net.silentclient.client.mods.render.skins.render.CustomizableModelPart;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public class BodyLayerFeatureRenderer
implements LayerRenderer<AbstractClientPlayer> {
private RenderPlayer playerRenderer;
private final boolean thinArms;
private static final Minecraft mc = Minecraft.getMinecraft();
public BodyLayerFeatureRenderer(
RenderPlayer playerRenderer) {
this.playerRenderer = playerRenderer;
thinArms = ((PlayerEntityModelAccessor)playerRenderer).client$hasThinArms();
bodyLayers.add(new Layer(0, false, EnumPlayerModelParts.LEFT_PANTS_LEG, Shape.LEGS, () -> playerRenderer.getMainModel().bipedLeftLeg, () -> Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Left Pants").getValBoolean()));
bodyLayers.add(new Layer(1, false, EnumPlayerModelParts.RIGHT_PANTS_LEG, Shape.LEGS, () -> playerRenderer.getMainModel().bipedRightLeg, () -> Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Right Pants").getValBoolean()));
bodyLayers.add(new Layer(2, false, EnumPlayerModelParts.LEFT_SLEEVE, thinArms ? Shape.ARMS_SLIM : Shape.ARMS, () -> playerRenderer.getMainModel().bipedLeftArm, () -> Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Left Sleeve").getValBoolean()));
bodyLayers.add(new Layer(3, true, EnumPlayerModelParts.RIGHT_SLEEVE, thinArms ? Shape.ARMS_SLIM : Shape.ARMS, () -> playerRenderer.getMainModel().bipedRightArm, () -> Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Right Sleeve").getValBoolean()));
bodyLayers.add(new Layer(4, false, EnumPlayerModelParts.JACKET, Shape.BODY, () -> playerRenderer.getMainModel().bipedBody, () -> Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Jacket").getValBoolean()));
}
@Override
public void doRenderLayer(AbstractClientPlayer player, float paramFloat1, float paramFloat2, float paramFloat3,
float deltaTick, float paramFloat5, float paramFloat6, float paramFloat7) {
if (!player.hasSkin() || player.isInvisible()) {
return;
}
if(mc.theWorld == null) {
return; // in a menu or something and the model gets rendered
}
if(mc.thePlayer.getPositionVector().squareDistanceTo(player.getPositionVector()) > Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Level Of Detail Distance").getValInt()*Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Level Of Detail Distance").getValInt())return;
PlayerSettings settings = (PlayerSettings) player;
// check for it being setup first to speedup the rendering
if(settings.client$getSkinLayers() == null && !setupModel(player, settings)) {
return; // no head layer setup and wasn't able to setup
}
//this.playerRenderer.bindTexture(player.getLocationSkin());
renderLayers(player, (CustomizableModelPart[]) settings.client$getSkinLayers(), deltaTick);
}
private boolean setupModel(AbstractClientPlayer abstractClientPlayerEntity, PlayerSettings settings) {
if(!SkinUtil.hasCustomSkin(abstractClientPlayerEntity)) {
return false; // default skin
}
SkinUtil.setup3dLayers(abstractClientPlayerEntity, settings, thinArms, null);
return true;
}
private final List<Layer> bodyLayers = new ArrayList<>();
class Layer{
int layersId;
boolean mirrored;
EnumPlayerModelParts modelPart;
Shape shape;
Supplier<ModelRenderer> vanillaGetter;
Supplier<Boolean> configGetter;
public Layer(int layersId, boolean mirrored, EnumPlayerModelParts modelPart, Shape shape,
Supplier<ModelRenderer> vanillaGetter, Supplier<Boolean> configGetter) {
this.layersId = layersId;
this.mirrored = mirrored;
this.modelPart = modelPart;
this.shape = shape;
this.vanillaGetter = vanillaGetter;
this.configGetter = configGetter;
}
}
private enum Shape {
HEAD(0), BODY(0.6f), LEGS(-0.2f), ARMS(0.4f), ARMS_SLIM(0.4f)
;
private final float yOffsetMagicValue;
private Shape(float yOffsetMagicValue) {
this.yOffsetMagicValue = yOffsetMagicValue;
}
}
public void renderLayers(AbstractClientPlayer abstractClientPlayer, CustomizableModelPart[] layers, float deltaTick) {
if(layers == null)return;
float pixelScaling = Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Voxel Size").getValFloat();
float heightScaling = 1.035f;
float widthScaling = Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Voxel Size").getValFloat();
// Overlay refuses to work correctly, this is a workaround for now
boolean redTint = abstractClientPlayer.hurtTime > 0 || abstractClientPlayer.deathTime > 0;
for(Layer layer : bodyLayers) {
if(abstractClientPlayer.isWearing(layer.modelPart) && !layer.vanillaGetter.get().isHidden && layer.configGetter.get()) {
GlStateManager.pushMatrix();
if(abstractClientPlayer.isSneaking()) {
GlStateManager.translate(0.0F, 0.2F, 0.0F);
}
layer.vanillaGetter.get().postRender(0.0625F);
if(layer.shape == Shape.ARMS) {
layers[layer.layersId].x = 0.998f*16;
} else if(layer.shape == Shape.ARMS_SLIM) {
layers[layer.layersId].x = 0.499f*16;
}
if(layer.shape == Shape.BODY) {
widthScaling = Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Body Voxel Width Size").getValFloat();
}else {
widthScaling = Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Voxel Size").getValFloat();
}
if(layer.mirrored) {
layers[layer.layersId].x *= -1;
}
GlStateManager.scale(0.0625, 0.0625, 0.0625);
GlStateManager.scale(widthScaling, heightScaling, pixelScaling);
layers[layer.layersId].y = layer.shape.yOffsetMagicValue;
layers[layer.layersId].render(redTint);
GlStateManager.popMatrix();
}
}
}
@Override
public boolean shouldCombineTextures() {
return false;
}
}

View File

@ -0,0 +1,90 @@
package net.silentclient.client.mods.render.skins.renderlayers;
import com.google.common.collect.Sets;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderPlayer;
import net.minecraft.client.renderer.entity.layers.LayerRenderer;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.silentclient.client.Client;
import net.silentclient.client.mixin.accessors.skins.PlayerEntityModelAccessor;
import net.silentclient.client.mixin.accessors.skins.PlayerSettings;
import net.silentclient.client.mods.render.skins.SkinUtil;
import net.silentclient.client.mods.render.skins.SkinsMod;
import java.util.Set;
public class HeadLayerFeatureRenderer implements LayerRenderer<AbstractClientPlayer> {
private Set<Item> hideHeadLayers = Sets.newHashSet(Items.skull);
private final boolean thinArms;
private static final Minecraft mc = Minecraft.getMinecraft();
private RenderPlayer playerRenderer;
public HeadLayerFeatureRenderer(RenderPlayer playerRenderer) {
thinArms = ((PlayerEntityModelAccessor)playerRenderer).client$hasThinArms();
this.playerRenderer = playerRenderer;
}
@Override
public void doRenderLayer(AbstractClientPlayer player, float paramFloat1, float paramFloat2, float paramFloat3,
float deltaTick, float paramFloat5, float paramFloat6, float paramFloat7) {
if (!player.hasSkin() || player.isInvisible() || !Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "3D Hat").getValBoolean()) {
return;
}
if(mc.thePlayer.getPositionVector().squareDistanceTo(player.getPositionVector()) > Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Level Of Detail Distance").getValInt()*Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Level Of Detail Distance").getValInt())return;
ItemStack itemStack = player.getEquipmentInSlot(1); //TODO
if (itemStack != null && hideHeadLayers.contains(itemStack.getItem())) {
return;
}
PlayerSettings settings = (PlayerSettings) player;
// check for it being setup first to speedup the rendering
if(settings.client$getHeadLayers() == null && !setupModel(player, settings)) {
return; // no head layer setup and wasn't able to setup
}
//this.playerRenderer.bindTexture(player.getLocationSkin());
renderCustomHelmet(settings, player, deltaTick);
}
private boolean setupModel(AbstractClientPlayer abstractClientPlayerEntity, PlayerSettings settings) {
if(!SkinUtil.hasCustomSkin(abstractClientPlayerEntity)) {
return false; // default skin
}
SkinUtil.setup3dLayers(abstractClientPlayerEntity, settings, thinArms, null);
return true;
}
public void renderCustomHelmet(PlayerSettings settings, AbstractClientPlayer abstractClientPlayer, float deltaTick) {
if(settings.client$getHeadLayers() == null)return;
if(playerRenderer.getMainModel().bipedHead.isHidden)return;
float voxelSize = Client.getInstance().getSettingsManager().getSettingByClass(SkinsMod.class, "Head Voxel Size").getValFloat();
GlStateManager.pushMatrix();
if(abstractClientPlayer.isSneaking()) {
GlStateManager.translate(0.0F, 0.2F, 0.0F);
}
playerRenderer.getMainModel().bipedHead.postRender(0.0625F);
//this.getParentModel().head.translateAndRotate(matrixStack);
GlStateManager.scale(0.0625, 0.0625, 0.0625);
GlStateManager.scale(voxelSize, voxelSize, voxelSize);
// Overlay refuses to work correctly, this is a workaround for now
boolean tintRed = abstractClientPlayer.hurtTime > 0 || abstractClientPlayer.deathTime > 0;
settings.client$getHeadLayers().render(tintRed);
GlStateManager.popMatrix();
}
@Override
public boolean shouldCombineTextures() {
return false;
}
}

View File

@ -123,6 +123,9 @@
"mixins.emotes.EntityPlayerMixin",
"mixins.emotes.MinecraftMixin",
"mixins.emotes.RenderPlayerMixin",
"mixins.lwjgl.WindowsDisplayMixin"
"mixins.lwjgl.WindowsDisplayMixin",
"mixins.skins.PlayerMixin",
"mixins.skins.PlayerRendererMixin",
"mixins.skins.RendererLivingEntityMixin"
]
}