Merge pull request #136 from DrPerkyLegit/fix/armor-stands

Fix/armor stands
This commit is contained in:
Fireblade 2026-05-31 14:33:10 -04:00 committed by GitHub
commit d421708b5f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 270 additions and 10 deletions

View file

@ -8,7 +8,6 @@ ArmorStandModel::ArmorStandModel(float scale) : HumanoidModel(scale)
{
texWidth = 64;
texHeight = 64;
head = new ModelPart(this, 0, 0);
head->addBox(-1.0f, -7.0f, -1.0f, 2, 7, 2, scale);

View file

@ -16,6 +16,7 @@
#include "PlayerRenderer.h"
#include "../Minecraft.World/SkullItem.h"
#include "../Minecraft.World/SkullTileEntity.h"
#include "../Minecraft.World/ElytraItem.h"
static const float DEG_TO_RAD = 3.14159265f / 180.0f;
@ -84,9 +85,22 @@ void ArmorStandRenderer::render(shared_ptr<Entity> entity,
double x, double y, double z,
float rot, float a)
{
shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(entity);
float brightness = SharedConstants::TEXTURE_LIGHTING ? 1 : mob->getBrightness(a);
glColor3f(brightness, brightness, brightness);
shared_ptr<ItemInstance> item = mob->getCarriedItem();
prepareCarriedItem(mob, item);
LivingEntityRenderer::render(entity, x, y, z, rot, a);
}
void ArmorStandRenderer::prepareCarriedItem(shared_ptr<Entity> mob, shared_ptr<ItemInstance> item)
{
armorLayer->armorModel1->holdingRightHand = armorLayer->armorModel2->holdingRightHand = item != nullptr ? 1 : 0;
}
void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRotMinusBodyRot,
@ -165,7 +179,109 @@ void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
void ArmorStandRenderer::additionalRendering(shared_ptr<LivingEntity> mob, float a)
{
{
shared_ptr<ItemInstance> chestItem = mob->getEquipmentSlots()[ArmorStand::SLOT_CHEST];
if (chestItem != nullptr && dynamic_cast<ElytraItem*>(chestItem->getItem()) != nullptr)
{
static ResourceLocation elytraTexture(L"item/elytra.png");
bindTexture(&elytraTexture);
float brightness2 = SharedConstants::TEXTURE_LIGHTING ? 1 : mob->getBrightness(a);
glColor3f(brightness2, brightness2, brightness2);
ArmorStandModel* standModel = ((ArmorStandModel*)this->model);
ArmorStand* stand = dynamic_cast<ArmorStand*>(mob.get());
float wf = 0.2617994f;
float wf1 = -0.2617994f;
float wf2 = standModel->body->y;
float wf3 = 0.0f;
stand->rotateElytraX += (wf - stand->rotateElytraX) * 0.3f;
stand->rotateElytraY += (wf3 - stand->rotateElytraY) * 0.3f;
stand->rotateElytraZ += (wf1 - stand->rotateElytraZ) * 0.3f;
standModel->elytraRight->y = wf2;
standModel->elytraRight->xRot = stand->rotateElytraX;
standModel->elytraRight->yRot = stand->rotateElytraY;
standModel->elytraRight->zRot = stand->rotateElytraZ;
standModel->elytraLeft->y = wf2;
standModel->elytraLeft->xRot = stand->rotateElytraX;
standModel->elytraLeft->yRot = -stand->rotateElytraY;
standModel->elytraLeft->zRot = -stand->rotateElytraZ;
glPushMatrix();
glTranslatef(0, 0.0f, (2.0f + 0.125f) / 16.0f);
standModel->renderElytra(1 / 16.0f, true);
glPopMatrix();
}
}
std::shared_ptr<ItemInstance> item = mob->getCarriedItem();
if (item != nullptr)
{
glPushMatrix();
ArmorStandModel* standModel = ((ArmorStandModel*)model);
if (standModel->young) {
float s = 0.5f;
glTranslatef(0 / 16.0f, 10 / 16.0f, 0 / 16.0f);
glRotatef(-20, -1, 0, 0);
glScalef(s, s, s);
}
standModel->arm1->translateTo(1 / 16.0f);
glTranslatef(-1 / 16.0f, 7 / 16.0f, 1 / 16.0f);
if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape()) && item->id != Tile::barrier_Id)
{
float s = 8 / 16.0f;
glTranslatef(-0 / 16.0f, 3 / 16.0f, -5 / 16.0f);
s *= 0.75f;
glRotatef(20, 1, 0, 0);
glRotatef(45, 0, 1, 0);
glScalef(-s, -s, s);
}
else if (item->id == Item::bow_Id)
{
float s = 10 / 16.0f;
glTranslatef(0 / 16.0f, 2 / 16.0f, 5 / 16.0f);
glRotatef(-20, 0, 1, 0);
glScalef(s, -s, s);
glRotatef(-100, 1, 0, 0);
glRotatef(45, 0, 1, 0);
}
else if (Item::items[item->id]->isHandEquipped())
{
float s = 10 / 16.0f;
glTranslatef(0, 3 / 16.0f, 0);
glScalef(s, -s, s);
glRotatef(-100, 1, 0, 0);
glRotatef(45, 0, 1, 0);
}
else
{
float s = 6 / 16.0f;
glTranslatef(+4 / 16.0f, +3 / 16.0f, -3 / 16.0f);
glScalef(s, s, s);
glRotatef(60, 0, 0, 1);
glRotatef(-90, 1, 0, 0);
glRotatef(20, 0, 0, 1);
}
this->entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item, 0);
if (item->getItem()->hasMultipleSpriteLayers())
{
this->entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item, 1);
}
glPopMatrix();
}
}

View file

@ -47,5 +47,7 @@ public:
float headRotMinusBodyRot,
float headRotx, float scale) override;
virtual int prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a) override;
void prepareCarriedItem(shared_ptr<Entity> mob, shared_ptr<ItemInstance> item);
virtual void additionalRendering(shared_ptr<LivingEntity> mob, float a) override;
};

View file

@ -13,11 +13,19 @@
#include "../Minecraft.World/SkullTileEntity.h"
#include "../Minecraft.World/LivingEntity.h"
#include "../Minecraft.World/Facing.h"
#include "../Minecraft.Client/SimpleIcon.h"
#include "../Minecraft.World/AirTile.h"
CustomHeadLayer::CustomHeadLayer(ModelPart* headPart, LivingEntityRenderer* parentRenderer)
: headPart(headPart), parentRenderer(parentRenderer)
{
tileRenderer = new TileRenderer();
}
CustomHeadLayer::~CustomHeadLayer() {
delete tileRenderer;
}
int CustomHeadLayer::colorsOnDamage()
@ -90,12 +98,136 @@ void CustomHeadLayer::render(shared_ptr<LivingEntity> mob,
glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
Minecraft* mc = Minecraft::GetInstance();
if (mc)
{
auto* iihr = mc->getItemInHandRenderer();
if (iihr)
iihr->renderItem(mob, helmet, 0, true);
// 4J - code borrowed from render method below, although not factoring in brightness as that should already be being taken into account
// by texture lighting. This is for colourising things held in 3rd person view.
if ((item != nullptr)) {
int col = Item::items[item->id]->getColor(helmet, 0);
float red = ((col >> 16) & 0xff) / 255.0f;
float g = ((col >> 8) & 0xff) / 255.0f;
float b = ((col) & 0xff) / 255.0f;
glColor4f(red, g, b, 1);
}
Minecraft* minecraft = Minecraft::GetInstance();
glPushMatrix();
Tile* tile = Tile::tiles[item->id];
if ((item->getIconType() == Icon::TYPE_TERRAIN && tile != nullptr && TileRenderer::canRender(tile->getRenderShape())) && item->id != AirTile::barrier_Id)
{
MemSect(31);
minecraft->textures->bindTexture(minecraft->textures->getTextureLocation(Icon::TYPE_TERRAIN));
MemSect(0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
tileRenderer->renderTile(Tile::tiles[item->id], helmet->getAuxValue(), SharedConstants::TEXTURE_LIGHTING ? 1.0f : mob->getBrightness(1)); // 4J - change brought forward from 1.8.2
glDisable(GL_BLEND);
}
else
{
MemSect(31);
Icon* icon = mob->getItemInHandIcon(helmet, 0);
if (icon == nullptr)
{
glPopMatrix();
MemSect(0);
return;
}
bool bIsTerrain = item->getIconType() == Icon::TYPE_TERRAIN;
minecraft->textures->bindTexture(minecraft->textures->getTextureLocation(item->getIconType()));
MemSect(0);
Tesselator* t = Tesselator::getInstance();
// Consider forcing the mipmap LOD level to use, if this is to be rendered from a larger than standard source texture.
int iconWidth = icon->getWidth();
int LOD = -1; // Default to not doing anything special with LOD forcing
if (iconWidth == 32)
{
LOD = 1; // Force LOD level 1 to achieve texture reads from 256x256 map
}
else if (iconWidth == 64)
{
LOD = 2; // Force LOD level 2 to achieve texture reads from 256x256 map
}
RenderManager.StateSetForceLOD(LOD);
// 4J Original comment
// Yes, these are backwards.
// No, I don't know why.
// 4J Stu - Make them the right way round...u coords were swapped
float u0 = icon->getU0();
float u1 = icon->getU1();
float v0 = icon->getV0();
float v1 = icon->getV1();
float xo = 0.0f;
float yo = 0.3f;
// Re position height of held item if skin is small
if (mob->getAnimOverrideBitmask() & (1 << HumanoidModel::eAnim_SmallModel))
{
if (mob->isRiding())
{
std::shared_ptr<Entity> ridingEntity = mob->riding;
if (ridingEntity != nullptr) // Safety check;
{
yo += 0.3f; // reverts the change in Boat.cpp for smaller models.
}
}
}
glEnable(GL_RESCALE_NORMAL);
glTranslatef(-xo, -yo, 0);
glScalef(1, 1, 1);
glRotatef(90, 0, 1, 0);
glTranslatef(-7.5f / 16.0f, 9 / 16.0f, 0);
glTranslatef(0, 0.03f, 0);
float dd = 1 / 16.0f;
ItemInHandRenderer::renderItem3D(t, u0, v0, u1, v1, icon->getSourceWidth(), icon->getSourceHeight(), 1 / 16.0f, false, bIsTerrain);
if (item != nullptr && helmet->isFoil())
{
glDepthFunc(GL_EQUAL);
glDisable(GL_LIGHTING);
minecraft->textures->bindTexture(&ItemInHandRenderer::ENCHANT_GLINT_LOCATION);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE);
float br = 0.76f;
glColor4f(0.5f * br, 0.25f * br, 0.8f * br, 1); // MGH - for some reason this colour isn't making it through to the render, so I've added to the tesselator for the glint geom above
glMatrixMode(GL_TEXTURE);
glPushMatrix();
float ss = 1 / 8.0f;
glScalef(ss, ss, ss);
float sx = Minecraft::currentTimeMillis() % (3000) / (3000.0f) * 8;
glTranslatef(sx, 0, 0);
glRotatef(-50, 0, 0, 1);
ItemInHandRenderer::renderItem3D(t, 0, 0, 1, 1, 256, 256, 1 / 16.0f, true, bIsTerrain);
glPopMatrix();
glPushMatrix();
glScalef(ss, ss, ss);
sx = System::currentTimeMillis() % (3000 + 1873) / (3000 + 1873.0f) * 8;
glTranslatef(-sx, 0, 0);
glRotatef(10, 0, 0, 1);
ItemInHandRenderer::renderItem3D(t, 0, 0, 1, 1, 256, 256, 1 / 16.0f, true, bIsTerrain);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glDisable(GL_BLEND);
glEnable(GL_LIGHTING);
glDepthFunc(GL_LEQUAL);
}
RenderManager.StateSetForceLOD(-1);
glDisable(GL_RESCALE_NORMAL);
}
glPopMatrix();
}
}

View file

@ -4,14 +4,17 @@
class ModelPart;
class LivingEntity;
class LivingEntityRenderer;
class TileRenderer;
class CustomHeadLayer : public RenderLayer {
public:
ModelPart* headPart;
LivingEntityRenderer* parentRenderer;
TileRenderer* tileRenderer;
CustomHeadLayer(ModelPart* headPart, LivingEntityRenderer* parentRenderer);
virtual ~CustomHeadLayer() {}
virtual ~CustomHeadLayer();
virtual int colorsOnDamage() override;
virtual void render(shared_ptr<LivingEntity> mob,

View file

@ -19,8 +19,8 @@
const Rotations ArmorStand::DEFAULT_HEAD_POSE (0.0f, 0.0f, 0.0f);
const Rotations ArmorStand::DEFAULT_BODY_POSE (0.0f, 0.0f, 0.0f);
const Rotations ArmorStand::DEFAULT_LEFT_ARM_POSE (-10.0f, 0.0f, -10.0f);
const Rotations ArmorStand::DEFAULT_RIGHT_ARM_POSE (-15.0f, 0.0f, 10.0f);
const Rotations ArmorStand::DEFAULT_LEFT_ARM_POSE (-15.0f, 0.0f, 10.0f);
const Rotations ArmorStand::DEFAULT_RIGHT_ARM_POSE (-10.0f, 0.0f, -10.0f);
const Rotations ArmorStand::DEFAULT_LEFT_LEG_POSE (-1.0f, 0.0f, -1.0f);
const Rotations ArmorStand::DEFAULT_RIGHT_LEG_POSE (1.0f, 0.0f, 1.0f);
@ -45,6 +45,10 @@ void ArmorStand::init()
for (int i = 0; i < equipmentCount; i++)
equipment[i] = nullptr;
rotateElytraX = 0.2617994f;
rotateElytraY = 0.0f;
rotateElytraZ = -0.2617994f;
headPose = DEFAULT_HEAD_POSE;
bodyPose = DEFAULT_BODY_POSE;
leftArmPose = DEFAULT_LEFT_ARM_POSE;

View file

@ -56,6 +56,10 @@ private:
bool isMarkerFlag;
bool noPhysics;
float standDamage;
public:
float rotateElytraX;
float rotateElytraY;
float rotateElytraZ;
public:
long long lastHit;