mirror of
https://github.com/neoStudiosLCE/neoLegacy.git
synced 2026-08-20 09:57:09 +00:00
fix: armorstand according to wiki + wobble animation + head renderer
Armor stands are not damaged by cacti but can be broken by arrows. An armor stand destroyed by an explosion or a firework does not drop as an item. Armor stands in water and lava at the same time are not consumed by the lava.
This commit is contained in:
parent
22953367f4
commit
f2cfbafc26
|
|
@ -1,27 +1,29 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include "HumanoidMobRenderer.h"
|
||||||
#include "ArmorStandRenderer.h"
|
#include "ArmorStandRenderer.h"
|
||||||
#include "ArmorStandModel.h"
|
|
||||||
#include "ArmorStandArmorModel.h"
|
#include "ArmorStandArmorModel.h"
|
||||||
#include "HumanoidModel.h"
|
#include "HumanoidModel.h"
|
||||||
#include "ItemInHandLayer.h"
|
#include "ArmorStandModel.h"
|
||||||
#include "CustomHeadLayer.h"
|
#include "CustomHeadLayer.h"
|
||||||
#include "Textures.h"
|
#include "Textures.h"
|
||||||
#include "HumanoidMobRenderer.h"
|
|
||||||
#include "../Minecraft.World/ArmorStand.h"
|
#include "../Minecraft.World/ArmorStand.h"
|
||||||
#include "../Minecraft.World/ArmorItem.h"
|
#include "../Minecraft.World/ArmorItem.h"
|
||||||
|
#include "../Minecraft.World/Tile.h"
|
||||||
|
#include "../Minecraft.World/Facing.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include "EntityRenderDispatcher.h"
|
||||||
|
#include "SkullTileRenderer.h"
|
||||||
|
#include "PlayerRenderer.h"
|
||||||
|
#include "../Minecraft.World/SkullItem.h"
|
||||||
|
#include "../Minecraft.World/SkullTileEntity.h"
|
||||||
|
|
||||||
static const float DEG_TO_RAD = 3.14159265f / 180.0f;
|
static const float DEG_TO_RAD = 3.14159265f / 180.0f;
|
||||||
|
|
||||||
ResourceLocation ArmorStandRenderer::LOC_ARMOR_STAND =
|
ResourceLocation ArmorStandRenderer::LOC_ARMOR_STAND = ResourceLocation(TN_MOB_ARMORSTAND);
|
||||||
ResourceLocation(TN_MOB_ARMORSTAND);
|
|
||||||
|
|
||||||
|
ArmorStandRenderer::ArmorStandArmorLayer::ArmorStandArmorLayer(LivingEntityRenderer* renderer)
|
||||||
|
|
||||||
ArmorStandRenderer::ArmorStandArmorLayer::ArmorStandArmorLayer(
|
|
||||||
LivingEntityRenderer* renderer)
|
|
||||||
: HumanoidArmorLayer(renderer)
|
: HumanoidArmorLayer(renderer)
|
||||||
{
|
{
|
||||||
|
|
||||||
delete armorModel1;
|
delete armorModel1;
|
||||||
delete armorModel2;
|
delete armorModel2;
|
||||||
armorModel1 = new ArmorStandArmorModel(0.5f);
|
armorModel1 = new ArmorStandArmorModel(0.5f);
|
||||||
|
|
@ -36,26 +38,15 @@ void ArmorStandRenderer::ArmorStandArmorLayer::createArmorModels()
|
||||||
armorModel2 = new ArmorStandArmorModel(1.0f);
|
armorModel2 = new ArmorStandArmorModel(1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ArmorStandRenderer::ArmorStandRenderer()
|
ArmorStandRenderer::ArmorStandRenderer()
|
||||||
: LivingEntityRenderer(new ArmorStandModel(0.0f), 0.0f)
|
: LivingEntityRenderer(new ArmorStandModel(0.0f), 0.0f)
|
||||||
{
|
{
|
||||||
|
armorLayer = new ArmorStandArmorLayer(this);
|
||||||
addLayer(new ArmorStandArmorLayer(this));
|
|
||||||
|
|
||||||
|
|
||||||
addLayer(new ItemInHandLayer(this));
|
|
||||||
|
|
||||||
|
|
||||||
ArmorStandModel* m = static_cast<ArmorStandModel*>(getModel());
|
ArmorStandModel* m = static_cast<ArmorStandModel*>(getModel());
|
||||||
addLayer(new CustomHeadLayer(m->head));
|
headLayer = m ? new CustomHeadLayer(m->head) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArmorStandRenderer::~ArmorStandRenderer()
|
ArmorStandRenderer::~ArmorStandRenderer() {}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceLocation* ArmorStandRenderer::getTextureLocation(shared_ptr<Entity> entity)
|
ResourceLocation* ArmorStandRenderer::getTextureLocation(shared_ptr<Entity> entity)
|
||||||
{
|
{
|
||||||
|
|
@ -64,29 +55,39 @@ ResourceLocation* ArmorStandRenderer::getTextureLocation(shared_ptr<Entity> enti
|
||||||
|
|
||||||
bool ArmorStandRenderer::shouldShowName(shared_ptr<LivingEntity> entity)
|
bool ArmorStandRenderer::shouldShowName(shared_ptr<LivingEntity> entity)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!entity) return false;
|
if (!entity) return false;
|
||||||
return entity->isCustomNameVisible();
|
return entity->isCustomNameVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArmorStandRenderer::setupRotations(shared_ptr<LivingEntity> mob,
|
void ArmorStandRenderer::setupRotations(shared_ptr<LivingEntity> mob,
|
||||||
float bob, float bodyRot, float a)
|
float bob, float bodyRot, float a)
|
||||||
{
|
{
|
||||||
|
shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(mob);
|
||||||
glRotatef(180.0f - bodyRot, 0.0f, 1.0f, 0.0f);
|
glRotatef(180.0f - bodyRot, 0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
|
if (stand)
|
||||||
|
{
|
||||||
|
long long ticksSinceHit = (long long)stand->tickCount - stand->lastHit;
|
||||||
|
if (ticksSinceHit >= 0 && ticksSinceHit < 5)
|
||||||
|
{
|
||||||
|
float wobble = (float)(ticksSinceHit + a) / 5.0f;
|
||||||
|
float angle = (float)stand->hurtDir * sinf(wobble * 3.14159265f) * 3.0f;
|
||||||
|
glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArmorStandRenderer::render(shared_ptr<Entity> entity,
|
void ArmorStandRenderer::render(shared_ptr<Entity> entity,
|
||||||
double x, double y, double z,
|
double x, double y, double z,
|
||||||
float rot, float a)
|
float rot, float a)
|
||||||
{
|
{
|
||||||
LivingEntityRenderer::render(entity, x, y, z, rot, a);
|
LivingEntityRenderer::render(entity, x, y, z, rot, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
|
void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
|
||||||
float wp, float ws, float bob,
|
float wp, float ws, float bob,
|
||||||
float headRotMinusBodyRot,
|
float headRotMinusBodyRot,
|
||||||
float headRotx, float scale)
|
float headRotx, float scale)
|
||||||
{
|
{
|
||||||
shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(mob);
|
shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(mob);
|
||||||
if (!stand) return;
|
if (!stand) return;
|
||||||
|
|
@ -94,7 +95,6 @@ void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
|
||||||
ArmorStandModel* m = static_cast<ArmorStandModel*>(getModel());
|
ArmorStandModel* m = static_cast<ArmorStandModel*>(getModel());
|
||||||
if (!m) return;
|
if (!m) return;
|
||||||
|
|
||||||
|
|
||||||
Rotations h = stand->getHeadPose();
|
Rotations h = stand->getHeadPose();
|
||||||
Rotations b = stand->getBodyPose();
|
Rotations b = stand->getBodyPose();
|
||||||
Rotations la = stand->getLeftArmPose();
|
Rotations la = stand->getLeftArmPose();
|
||||||
|
|
@ -102,120 +102,151 @@ void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
|
||||||
Rotations ll = stand->getLeftLegPose();
|
Rotations ll = stand->getLeftLegPose();
|
||||||
Rotations rl = stand->getRightLegPose();
|
Rotations rl = stand->getRightLegPose();
|
||||||
|
|
||||||
|
|
||||||
m->setupPose(
|
m->setupPose(
|
||||||
h.getX() * DEG_TO_RAD, h.getY() * DEG_TO_RAD, h.getZ() * DEG_TO_RAD,
|
h.x * DEG_TO_RAD, h.y * DEG_TO_RAD, h.z * DEG_TO_RAD,
|
||||||
b.getX() * DEG_TO_RAD, b.getY() * DEG_TO_RAD, b.getZ() * DEG_TO_RAD,
|
b.x * DEG_TO_RAD, b.y * DEG_TO_RAD, b.z * DEG_TO_RAD,
|
||||||
la.getX() * DEG_TO_RAD, la.getY() * DEG_TO_RAD, la.getZ() * DEG_TO_RAD,
|
la.x * DEG_TO_RAD, la.y * DEG_TO_RAD, la.z * DEG_TO_RAD,
|
||||||
ra.getX() * DEG_TO_RAD, ra.getY() * DEG_TO_RAD, ra.getZ() * DEG_TO_RAD,
|
ra.x * DEG_TO_RAD, ra.y * DEG_TO_RAD, ra.z * DEG_TO_RAD,
|
||||||
ll.getX() * DEG_TO_RAD, ll.getY() * DEG_TO_RAD, ll.getZ() * DEG_TO_RAD,
|
ll.x * DEG_TO_RAD, ll.y * DEG_TO_RAD, ll.z * DEG_TO_RAD,
|
||||||
rl.getX() * DEG_TO_RAD, rl.getY() * DEG_TO_RAD, rl.getZ() * DEG_TO_RAD
|
rl.x * DEG_TO_RAD, rl.y * DEG_TO_RAD, rl.z * DEG_TO_RAD
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (armorLayer)
|
||||||
ArmorStandArmorLayer* al = getArmorLayer();
|
|
||||||
|
|
||||||
if (al)
|
|
||||||
{
|
{
|
||||||
auto applyPose = [&](HumanoidModel* am)
|
auto applyPose = [&](HumanoidModel* am)
|
||||||
{
|
{
|
||||||
if (!am) return;
|
if (!am) return;
|
||||||
|
am->head->xRot = h.x * DEG_TO_RAD; am->head->yRot = h.y * DEG_TO_RAD; am->head->zRot = h.z * DEG_TO_RAD;
|
||||||
|
if (am->hair) { am->hair->xRot = h.x * DEG_TO_RAD; am->hair->yRot = h.y * DEG_TO_RAD; am->hair->zRot = h.z * DEG_TO_RAD; }
|
||||||
am->head->xRot = h.getX() * DEG_TO_RAD;
|
am->body->xRot = b.x * DEG_TO_RAD; am->body->yRot = b.y * DEG_TO_RAD; am->body->zRot = b.z * DEG_TO_RAD;
|
||||||
am->head->yRot = h.getY() * DEG_TO_RAD;
|
am->arm1->xRot = la.x * DEG_TO_RAD; am->arm1->yRot = la.y * DEG_TO_RAD; am->arm1->zRot = la.z * DEG_TO_RAD;
|
||||||
am->head->zRot = h.getZ() * DEG_TO_RAD;
|
am->arm0->xRot = ra.x * DEG_TO_RAD; am->arm0->yRot = ra.y * DEG_TO_RAD; am->arm0->zRot = ra.z * DEG_TO_RAD;
|
||||||
if (am->hair) {
|
am->leg0->xRot = rl.x * DEG_TO_RAD; am->leg0->yRot = rl.y * DEG_TO_RAD; am->leg0->zRot = rl.z * DEG_TO_RAD;
|
||||||
am->hair->xRot = h.getX() * DEG_TO_RAD;
|
am->leg1->xRot = ll.x * DEG_TO_RAD; am->leg1->yRot = ll.y * DEG_TO_RAD; am->leg1->zRot = ll.z * DEG_TO_RAD;
|
||||||
am->hair->yRot = h.getY() * DEG_TO_RAD;
|
|
||||||
am->hair->zRot = h.getZ() * DEG_TO_RAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
am->body->xRot = b.getX() * DEG_TO_RAD;
|
|
||||||
am->body->yRot = b.getY() * DEG_TO_RAD;
|
|
||||||
am->body->zRot = b.getZ() * DEG_TO_RAD;
|
|
||||||
|
|
||||||
|
|
||||||
am->arm1->xRot = la.getX() * DEG_TO_RAD;
|
|
||||||
am->arm1->yRot = la.getY() * DEG_TO_RAD;
|
|
||||||
am->arm1->zRot = la.getZ() * DEG_TO_RAD;
|
|
||||||
|
|
||||||
|
|
||||||
am->arm0->xRot = ra.getX() * DEG_TO_RAD;
|
|
||||||
am->arm0->yRot = ra.getY() * DEG_TO_RAD;
|
|
||||||
am->arm0->zRot = ra.getZ() * DEG_TO_RAD;
|
|
||||||
|
|
||||||
|
|
||||||
am->leg0->xRot = rl.getX() * DEG_TO_RAD;
|
|
||||||
am->leg0->yRot = rl.getY() * DEG_TO_RAD;
|
|
||||||
am->leg0->zRot = rl.getZ() * DEG_TO_RAD;
|
|
||||||
|
|
||||||
|
|
||||||
am->leg1->xRot = ll.getX() * DEG_TO_RAD;
|
|
||||||
am->leg1->yRot = ll.getY() * DEG_TO_RAD;
|
|
||||||
am->leg1->zRot = ll.getZ() * DEG_TO_RAD;
|
|
||||||
};
|
};
|
||||||
|
applyPose(static_cast<HumanoidModel*>(armorLayer->armorModel1));
|
||||||
applyPose(static_cast<HumanoidModel*>(al->armorModel1));
|
applyPose(static_cast<HumanoidModel*>(armorLayer->armorModel2));
|
||||||
applyPose(static_cast<HumanoidModel*>(al->armorModel2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LivingEntityRenderer::renderModel(mob, wp, ws, bob,
|
LivingEntityRenderer::renderModel(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale);
|
||||||
headRotMinusBodyRot, headRotx, scale);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < renderLayers.size(); ++i) {
|
if (headLayer)
|
||||||
if (renderLayers[i]) {
|
{
|
||||||
renderLayers[i]->render(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale, true);
|
float fScale = 1.0f / 16.0f;
|
||||||
}
|
float bodyRot = mob->yBodyRotO + (mob->yBodyRot - mob->yBodyRotO) * 0.0f;
|
||||||
|
float headRot = mob->yHeadRotO + (mob->yHeadRot - mob->yHeadRotO) * 0.0f;
|
||||||
|
float headRotX = mob->xRotO + (mob->xRot - mob->xRotO) * 0.0f;
|
||||||
|
headLayer->render(mob, wp, ws, bob, headRot - bodyRot, headRotX, fScale, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ArmorStandRenderer::additionalRendering(shared_ptr<LivingEntity> mob, float a)
|
||||||
|
{
|
||||||
|
shared_ptr<ItemInstance> headGear = mob->getArmor(3);
|
||||||
|
if (!headGear) return;
|
||||||
|
|
||||||
|
if ((mob->getAnimOverrideBitmask() & (1 << HumanoidModel::eAnim_DontRenderArmour)) != 0) return;
|
||||||
|
|
||||||
|
if (headGear->getItem()->id >= 256) return;
|
||||||
|
|
||||||
|
ArmorStandModel* m = static_cast<ArmorStandModel*>(getModel());
|
||||||
|
if (!m || !m->head) return;
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
m->head->translateTo(1.0f / 16.0f);
|
||||||
|
|
||||||
|
if (Tile::tiles[headGear->id] != nullptr && TileRenderer::canRender(Tile::tiles[headGear->id]->getRenderShape()))
|
||||||
|
{
|
||||||
|
float s = 10.0f / 16.0f;
|
||||||
|
glTranslatef(0.0f, -4.0f / 16.0f, 0.0f);
|
||||||
|
glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
glScalef(s, -s, s);
|
||||||
|
}
|
||||||
|
this->entityRenderDispatcher->itemInHandRenderer->renderItem(mob, headGear, 0);
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
int ArmorStandRenderer::prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a)
|
int ArmorStandRenderer::prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a)
|
||||||
{
|
{
|
||||||
if (!armorLayer) return -1;
|
if (!armorLayer) return -1;
|
||||||
|
|
||||||
shared_ptr<ItemInstance> itemInstance = mob->getArmor(3 - layer);
|
shared_ptr<ItemInstance> itemInstance = mob->getArmor(3 - layer);
|
||||||
if (itemInstance != nullptr)
|
if (!itemInstance) return -1;
|
||||||
|
|
||||||
|
Item* item = itemInstance->getItem();
|
||||||
|
|
||||||
|
SkullItem* skullItem = dynamic_cast<SkullItem*>(item);
|
||||||
|
if (skullItem && layer == 0)
|
||||||
{
|
{
|
||||||
Item *item = itemInstance->getItem();
|
HumanoidModel* am = armorLayer->getArmorModel(layer);
|
||||||
ArmorItem *armorItem = dynamic_cast<ArmorItem *>(item);
|
|
||||||
if (armorItem != nullptr)
|
switch (itemInstance->getAuxValue())
|
||||||
{
|
{
|
||||||
bindTexture(HumanoidMobRenderer::getArmorLocation(armorItem, layer));
|
case SkullTileEntity::TYPE_WITHER:
|
||||||
|
bindTexture(&PlayerRenderer::WITHER_SKELETON_LOCATION);
|
||||||
HumanoidModel *am = armorLayer->getArmorModel(layer);
|
break;
|
||||||
|
case SkullTileEntity::TYPE_ZOMBIE:
|
||||||
am->head->visible = (layer == 0);
|
bindTexture(&PlayerRenderer::ZOMBIE_LOCATION);
|
||||||
if (am->hair) am->hair->visible = (layer == 0);
|
break;
|
||||||
am->body->visible = (layer == 1 || layer == 2);
|
case SkullTileEntity::TYPE_CREEPER:
|
||||||
am->arm0->visible = (layer == 1);
|
bindTexture(&PlayerRenderer::CREEPER_LOCATION);
|
||||||
am->arm1->visible = (layer == 1);
|
break;
|
||||||
am->leg0->visible = (layer == 2 || layer == 3);
|
case SkullTileEntity::TYPE_CHAR:
|
||||||
am->leg1->visible = (layer == 2 || layer == 3);
|
bindTexture(&PlayerRenderer::DEFAULT_LOCATION);
|
||||||
|
break;
|
||||||
setArmor(am);
|
case SkullTileEntity::TYPE_SKELETON:
|
||||||
am->attackTime = model->attackTime;
|
default:
|
||||||
am->riding = model->riding;
|
bindTexture(&PlayerRenderer::SKELETON_LOCATION);
|
||||||
am->young = mob->isBaby();
|
break;
|
||||||
|
|
||||||
if (armorItem->getMaterial() == ArmorItem::ArmorMaterial::CLOTH)
|
|
||||||
{
|
|
||||||
int color = armorItem->getColor(itemInstance);
|
|
||||||
float red = static_cast<float>((color >> 16) & 0xFF) / 255.0f;
|
|
||||||
float green = static_cast<float>((color >> 8) & 0xFF) / 255.0f;
|
|
||||||
float blue = static_cast<float>(color & 0xFF) / 255.0f;
|
|
||||||
glColor3f(red, green, blue);
|
|
||||||
|
|
||||||
if (itemInstance->isEnchanted()) return 0x1f;
|
|
||||||
return 0x10;
|
|
||||||
}
|
|
||||||
|
|
||||||
glColor3f(1.0f, 1.0f, 1.0f);
|
|
||||||
if (itemInstance->isEnchanted()) return 15;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
am->head->visible = true;
|
||||||
|
if (am->hair) am->hair->visible = false;
|
||||||
|
am->body->visible = false;
|
||||||
|
am->arm0->visible = false;
|
||||||
|
am->arm1->visible = false;
|
||||||
|
am->leg0->visible = false;
|
||||||
|
am->leg1->visible = false;
|
||||||
|
|
||||||
|
setArmor(am);
|
||||||
|
am->attackTime = model->attackTime;
|
||||||
|
am->riding = model->riding;
|
||||||
|
am->young = mob->isBaby();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
|
ArmorItem* armorItem = dynamic_cast<ArmorItem*>(item);
|
||||||
|
if (!armorItem) return -1;
|
||||||
|
|
||||||
|
bindTexture(HumanoidMobRenderer::getArmorLocation(armorItem, layer));
|
||||||
|
|
||||||
|
HumanoidModel* am = armorLayer->getArmorModel(layer);
|
||||||
|
am->head->visible = (layer == 0);
|
||||||
|
if (am->hair) am->hair->visible = (layer == 0);
|
||||||
|
am->body->visible = (layer == 1 || layer == 2);
|
||||||
|
am->arm0->visible = (layer == 1);
|
||||||
|
am->arm1->visible = (layer == 1);
|
||||||
|
am->leg0->visible = (layer == 2 || layer == 3);
|
||||||
|
am->leg1->visible = (layer == 2 || layer == 3);
|
||||||
|
|
||||||
|
setArmor(am);
|
||||||
|
am->attackTime = model->attackTime;
|
||||||
|
am->riding = model->riding;
|
||||||
|
am->young = mob->isBaby();
|
||||||
|
|
||||||
|
if (armorItem->getMaterial() == ArmorItem::ArmorMaterial::CLOTH)
|
||||||
|
{
|
||||||
|
int color = armorItem->getColor(itemInstance);
|
||||||
|
float red = static_cast<float>((color >> 16) & 0xFF) / 255.0f;
|
||||||
|
float green = static_cast<float>((color >> 8) & 0xFF) / 255.0f;
|
||||||
|
float blue = static_cast<float>(color & 0xFF) / 255.0f;
|
||||||
|
glColor3f(red, green, blue);
|
||||||
|
if (itemInstance->isEnchanted()) return 0x1f;
|
||||||
|
return 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
|
if (itemInstance->isEnchanted()) return 15;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
#include "LivingEntityRenderer.h"
|
#include "LivingEntityRenderer.h"
|
||||||
#include "HumanoidArmorLayer.h"
|
#include "HumanoidArmorLayer.h"
|
||||||
#include "ResourceLocation.h"
|
#include "ResourceLocation.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class ArmorStandModel;
|
class ArmorStandModel;
|
||||||
class LivingEntity;
|
class LivingEntity;
|
||||||
class Entity;
|
class Entity;
|
||||||
class RenderLayer;
|
class RenderLayer;
|
||||||
|
class CustomHeadLayer;
|
||||||
|
|
||||||
class ArmorStandRenderer : public LivingEntityRenderer {
|
class ArmorStandRenderer : public LivingEntityRenderer {
|
||||||
public:
|
public:
|
||||||
|
|
@ -22,17 +22,12 @@ public:
|
||||||
protected:
|
protected:
|
||||||
std::vector<RenderLayer*> renderLayers;
|
std::vector<RenderLayer*> renderLayers;
|
||||||
ArmorStandArmorLayer* armorLayer;
|
ArmorStandArmorLayer* armorLayer;
|
||||||
|
CustomHeadLayer* headLayer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void addLayer(RenderLayer* layer) {
|
void addLayer(RenderLayer* layer) { renderLayers.push_back(layer); }
|
||||||
renderLayers.push_back(layer);
|
void addLayer(ArmorStandArmorLayer* layer) { armorLayer = layer; }
|
||||||
}
|
ArmorStandArmorLayer* getArmorLayer() { return armorLayer; }
|
||||||
void addLayer(ArmorStandArmorLayer* layer) {
|
|
||||||
armorLayer = layer;
|
|
||||||
}
|
|
||||||
ArmorStandArmorLayer* getArmorLayer() {
|
|
||||||
return armorLayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ResourceLocation LOC_ARMOR_STAND;
|
static ResourceLocation LOC_ARMOR_STAND;
|
||||||
|
|
||||||
|
|
@ -41,14 +36,16 @@ public:
|
||||||
|
|
||||||
virtual ResourceLocation* getTextureLocation(shared_ptr<Entity> entity) override;
|
virtual ResourceLocation* getTextureLocation(shared_ptr<Entity> entity) override;
|
||||||
virtual bool shouldShowName(shared_ptr<LivingEntity> mob) override;
|
virtual bool shouldShowName(shared_ptr<LivingEntity> mob) override;
|
||||||
virtual void setupRotations(shared_ptr<LivingEntity> mob,
|
|
||||||
float bob, float bodyRot, float a) override;
|
virtual void setupRotations(shared_ptr<LivingEntity> mob,
|
||||||
virtual void render(shared_ptr<Entity> entity,
|
float bob, float bodyRot, float a) override;
|
||||||
double x, double y, double z,
|
virtual void render(shared_ptr<Entity> entity,
|
||||||
float rot, float a) override;
|
double x, double y, double z,
|
||||||
virtual void renderModel(shared_ptr<LivingEntity> mob,
|
float rot, float a) override;
|
||||||
float wp, float ws, float bob,
|
virtual void renderModel(shared_ptr<LivingEntity> mob,
|
||||||
float headRotMinusBodyRot,
|
float wp, float ws, float bob,
|
||||||
float headRotx, float scale) override;
|
float headRotMinusBodyRot,
|
||||||
virtual int prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a) override;
|
float headRotx, float scale) override;
|
||||||
|
virtual int prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a) override;
|
||||||
|
virtual void additionalRendering(shared_ptr<LivingEntity> mob, float a) override;
|
||||||
};
|
};
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "CustomHeadLayer.h"
|
#include "CustomHeadLayer.h"
|
||||||
#include "ModelPart.h"
|
#include "ModelPart.h"
|
||||||
|
#include "SkullTileRenderer.h"
|
||||||
|
#include "TileRenderer.h"
|
||||||
#include "../Minecraft.World/ItemInstance.h"
|
#include "../Minecraft.World/ItemInstance.h"
|
||||||
#include "../Minecraft.World/Item.h"
|
#include "../Minecraft.World/Item.h"
|
||||||
#include "../Minecraft.World/Tile.h"
|
#include "../Minecraft.World/Tile.h"
|
||||||
|
|
@ -11,7 +13,8 @@ CustomHeadLayer::CustomHeadLayer(ModelPart* headPart)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int CustomHeadLayer::colorsOnDamage() {
|
int CustomHeadLayer::colorsOnDamage()
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,59 +23,43 @@ void CustomHeadLayer::render(shared_ptr<LivingEntity> mob,
|
||||||
float headRot, float headRotX,
|
float headRot, float headRotX,
|
||||||
float scale, bool useCompiled)
|
float scale, bool useCompiled)
|
||||||
{
|
{
|
||||||
|
|
||||||
ItemInstanceArray slots = mob->getEquipmentSlots();
|
ItemInstanceArray slots = mob->getEquipmentSlots();
|
||||||
if (slots.length < 5) return;
|
if (slots.length < 5) return;
|
||||||
shared_ptr<ItemInstance> helmet = slots[4];
|
shared_ptr<ItemInstance> helmet = slots[4];
|
||||||
if (!helmet) return;
|
if (!helmet) return;
|
||||||
|
|
||||||
Item* item = helmet->getItem();
|
Item* item = helmet->getItem();
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
|
|
||||||
bool hasHatLayer = false;
|
bool hasHatLayer = false;
|
||||||
if (mob->instanceof(eTYPE_PLAYER)) {
|
if (mob->instanceof(eTYPE_PLAYER)) {
|
||||||
_SkinAdjustments adj;
|
_SkinAdjustments adj;
|
||||||
mob->getSkinAdjustments(&adj);
|
mob->getSkinAdjustments(&adj);
|
||||||
|
|
||||||
hasHatLayer = (adj.data[0] & 0x100) != 0;
|
hasHatLayer = (adj.data[0] & 0x100) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
|
||||||
|
|
||||||
headPart->translateTo(0.0625f);
|
headPart->translateTo(0.0625f);
|
||||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
int itemId = item->id;
|
int itemId = item->id;
|
||||||
|
|
||||||
if (itemId == Tile::skull_Id) {
|
if (itemId == Tile::skull_Id) {
|
||||||
|
if (!SkullTileRenderer::instance) { glPopMatrix(); return; }
|
||||||
glScalef(1.1875f, -1.1875f, -1.1875f);
|
glScalef(1.1875f, -1.1875f, -1.1875f);
|
||||||
if (hasHatLayer)
|
glTranslatef(-0.5f, 0.0f, -0.5f);
|
||||||
glTranslatef(0.0f, 0.0625f, 0.0f);
|
int skullType = helmet->getAuxValue() & 0xF;
|
||||||
|
wstring extra = helmet->hasTag() ? helmet->getTag()->getString(L"SkullOwner") : L"";
|
||||||
|
SkullTileRenderer::instance->renderSkull(0.0f, 0.0f, 0.0f, -1, 180.0f, skullType, extra);
|
||||||
|
} else if (itemId < 0x100) {
|
||||||
} else if (itemId < 0x100) {
|
glTranslatef(0.0f, -0.25f, 0.0f);
|
||||||
|
glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
|
||||||
glTranslatef(0.0f, -0.25f, 0.0f);
|
glScalef(0.625f, 0.625f, 0.625f);
|
||||||
glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
|
glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
|
||||||
glScalef(0.625f, -0.625f, -0.625f);
|
if (itemId > 0 && itemId < Tile::TILE_NUM_COUNT && Tile::tiles[itemId]) {
|
||||||
|
TileRenderer tr;
|
||||||
if (hasHatLayer)
|
tr.renderTile(Tile::tiles[itemId], helmet->getAuxValue(), 1.0f, 1.0f, useCompiled);
|
||||||
glTranslatef(0.0f, 0.1875f, 0.0f);
|
|
||||||
|
|
||||||
glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
|
|
||||||
|
|
||||||
|
|
||||||
if (itemId > 0 && itemId < Tile::TILE_NUM_COUNT && Tile::tiles[itemId]) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include "Textures.h"
|
#include "Textures.h"
|
||||||
#include "Skins.h"
|
#include "Skins.h"
|
||||||
|
|
||||||
|
|
||||||
ResourceLocation PlayerRenderer::SKELETON_LOCATION = ResourceLocation(TN_MOB_SKELETON);
|
ResourceLocation PlayerRenderer::SKELETON_LOCATION = ResourceLocation(TN_MOB_SKELETON);
|
||||||
ResourceLocation PlayerRenderer::WITHER_SKELETON_LOCATION = ResourceLocation(TN_MOB_WITHER_SKELETON);
|
ResourceLocation PlayerRenderer::WITHER_SKELETON_LOCATION = ResourceLocation(TN_MOB_WITHER_SKELETON);
|
||||||
ResourceLocation PlayerRenderer::ZOMBIE_LOCATION = ResourceLocation(TN_MOB_ZOMBIE);
|
ResourceLocation PlayerRenderer::ZOMBIE_LOCATION = ResourceLocation(TN_MOB_ZOMBIE);
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ private:
|
||||||
HumanoidModel *armorParts2;
|
HumanoidModel *armorParts2;
|
||||||
HumanoidModel *armorParts3;
|
HumanoidModel *armorParts3;
|
||||||
bool defaultSlimHands;
|
bool defaultSlimHands;
|
||||||
|
public:
|
||||||
static ResourceLocation SKELETON_LOCATION;
|
static ResourceLocation SKELETON_LOCATION;
|
||||||
static ResourceLocation WITHER_SKELETON_LOCATION;
|
static ResourceLocation WITHER_SKELETON_LOCATION;
|
||||||
static ResourceLocation ZOMBIE_LOCATION;
|
static ResourceLocation ZOMBIE_LOCATION;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include "../Minecraft.World/SetHealthPacket.h"
|
#include "../Minecraft.World/SetHealthPacket.h"
|
||||||
#include "../Minecraft.World/LevelSoundPacket.h"
|
#include "../Minecraft.World/LevelSoundPacket.h"
|
||||||
#include "../Minecraft.World/LevelParticlesPacket.h"
|
#include "../Minecraft.World/LevelParticlesPacket.h"
|
||||||
|
#include "../Minecraft.Client/ParticleType.h"
|
||||||
#include "../Minecraft.World/SetEntityLinkPacket.h"
|
#include "../Minecraft.World/SetEntityLinkPacket.h"
|
||||||
#include "../Minecraft.World/SimpleContainer.h"
|
#include "../Minecraft.World/SimpleContainer.h"
|
||||||
#include "../Minecraft.World/Slot.h"
|
#include "../Minecraft.World/Slot.h"
|
||||||
|
|
@ -633,9 +634,6 @@ int __cdecl NativeSendRaw(int entityId, unsigned char *bufferData, int bufferSiz
|
||||||
|
|
||||||
void WriteInventoryItemData(std::shared_ptr<ItemInstance> item, int index, int* outBuffer) {
|
void WriteInventoryItemData(std::shared_ptr<ItemInstance> item, int index, int* outBuffer) {
|
||||||
if (item) {
|
if (item) {
|
||||||
//ItemFlags Key:
|
|
||||||
// 0x1 = hasMetadata (has data that needs to be gotten from "ReadMetaFromNative")
|
|
||||||
|
|
||||||
uint8_t itemFlags = 0;
|
uint8_t itemFlags = 0;
|
||||||
if (item->getTag() == nullptr) goto doneWithMetadataFlag;
|
if (item->getTag() == nullptr) goto doneWithMetadataFlag;
|
||||||
CompoundTag* itemTag = item->getTag();
|
CompoundTag* itemTag = item->getTag();
|
||||||
|
|
@ -644,7 +642,7 @@ void WriteInventoryItemData(std::shared_ptr<ItemInstance> item, int index, int*
|
||||||
itemFlags |= 0x1;
|
itemFlags |= 0x1;
|
||||||
goto doneWithMetadataFlag;
|
goto doneWithMetadataFlag;
|
||||||
}
|
}
|
||||||
else { //we just want to check one tag for metadata and return for this flag, not all of them
|
else {
|
||||||
CompoundTag* displayTag = itemTag->getCompound(L"display");
|
CompoundTag* displayTag = itemTag->getCompound(L"display");
|
||||||
if (displayTag->contains(L"Name") || displayTag->contains(L"Lore")) {
|
if (displayTag->contains(L"Name") || displayTag->contains(L"Lore")) {
|
||||||
itemFlags |= 0x1;
|
itemFlags |= 0x1;
|
||||||
|
|
@ -652,9 +650,7 @@ void WriteInventoryItemData(std::shared_ptr<ItemInstance> item, int index, int*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
doneWithMetadataFlag:
|
doneWithMetadataFlag:
|
||||||
|
|
||||||
outBuffer[(index * 3) + 0] = item->id;
|
outBuffer[(index * 3) + 0] = item->id;
|
||||||
outBuffer[(index * 3) + 1] = item->getAuxValue();
|
outBuffer[(index * 3) + 1] = item->getAuxValue();
|
||||||
outBuffer[(index * 3) + 2] = (((int)itemFlags << 24) | ((int)item->count << 8));
|
outBuffer[(index * 3) + 2] = (((int)itemFlags << 24) | ((int)item->count << 8));
|
||||||
|
|
@ -663,9 +659,6 @@ void WriteInventoryItemData(std::shared_ptr<ItemInstance> item, int index, int*
|
||||||
|
|
||||||
void __cdecl NativeGetPlayerInventory(int entityId, int *outData)
|
void __cdecl NativeGetPlayerInventory(int entityId, int *outData)
|
||||||
{
|
{
|
||||||
// 9 slots per row, 3 slots in the inventory and the hotbar, 4 armor slots, 1 hand slot
|
|
||||||
// (((slotsPerRow * Rows) + ArmorSlots) * AmountOfIntsPerSlot) + hand slot
|
|
||||||
// (((9 * 4) + 4) * 3) + 1 = 121
|
|
||||||
memset(outData, 0, 121 * sizeof(int));
|
memset(outData, 0, 121 * sizeof(int));
|
||||||
|
|
||||||
auto player = FindPlayer(entityId);
|
auto player = FindPlayer(entityId);
|
||||||
|
|
@ -806,8 +799,7 @@ void __cdecl NativeOpenVirtualContainer(int entityId, int nativeType, const char
|
||||||
|
|
||||||
player->openContainer(container);
|
player->openContainer(container);
|
||||||
}
|
}
|
||||||
//didnt update this for enchants
|
|
||||||
// [nameLen:int32][nameUTF8:bytes][loreCount:int32][lore0Len:int32][lore0UTF8:bytes]
|
|
||||||
int __cdecl NativeGetItemMeta(int entityId, int slot, char *outBuf, int bufSize)
|
int __cdecl NativeGetItemMeta(int entityId, int slot, char *outBuf, int bufSize)
|
||||||
{
|
{
|
||||||
auto player = FindPlayer(entityId);
|
auto player = FindPlayer(entityId);
|
||||||
|
|
@ -829,7 +821,6 @@ int __cdecl NativeGetItemMeta(int entityId, int slot, char *outBuf, int bufSize)
|
||||||
CompoundTag *display = tag->getCompound(L"display");
|
CompoundTag *display = tag->getCompound(L"display");
|
||||||
bool hasName = display->contains(L"Name");
|
bool hasName = display->contains(L"Name");
|
||||||
bool hasLore = display->contains(L"Lore");
|
bool hasLore = display->contains(L"Lore");
|
||||||
|
|
||||||
bool hasEnchantments = item->isEnchanted();
|
bool hasEnchantments = item->isEnchanted();
|
||||||
|
|
||||||
if (!hasName && !hasLore)
|
if (!hasName && !hasLore)
|
||||||
|
|
@ -888,18 +879,14 @@ int __cdecl NativeGetItemMeta(int entityId, int slot, char *outBuf, int bufSize)
|
||||||
ListTag<CompoundTag>* list = item->getEnchantmentTags();
|
ListTag<CompoundTag>* list = item->getEnchantmentTags();
|
||||||
if (list != nullptr) {
|
if (list != nullptr) {
|
||||||
int listSize = list->size();
|
int listSize = list->size();
|
||||||
|
|
||||||
if ((offset + 4 + (listSize * (4 + 4))) > bufSize) return 0;
|
if ((offset + 4 + (listSize * (4 + 4))) > bufSize) return 0;
|
||||||
|
|
||||||
memcpy(outBuf + offset, &listSize, 4);
|
memcpy(outBuf + offset, &listSize, 4);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
for (int i = 0; i < listSize; i++) {
|
for (int i = 0; i < listSize; i++) {
|
||||||
int type = list->get(i)->getShort((wchar_t*)ItemInstance::TAG_ENCH_ID);
|
int type = list->get(i)->getShort((wchar_t*)ItemInstance::TAG_ENCH_ID);
|
||||||
int level = list->get(i)->getShort((wchar_t*)ItemInstance::TAG_ENCH_LEVEL);
|
int level = list->get(i)->getShort((wchar_t*)ItemInstance::TAG_ENCH_LEVEL);
|
||||||
|
|
||||||
memcpy(outBuf + offset, &type, 4);
|
memcpy(outBuf + offset, &type, 4);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
|
|
||||||
memcpy(outBuf + offset, &level, 4);
|
memcpy(outBuf + offset, &level, 4);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
}
|
}
|
||||||
|
|
@ -946,11 +933,8 @@ void __cdecl NativeSetItemMeta(int entityId, int slot, const char *inBuf, int bu
|
||||||
item->setTag(nullptr);
|
item->setTag(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag && tag->contains(L"ench"))
|
if (tag && tag->contains(L"ench"))
|
||||||
{
|
|
||||||
tag->remove(L"ench");
|
tag->remove(L"ench");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1030,15 +1014,12 @@ void __cdecl NativeSetItemMeta(int entityId, int slot, const char *inBuf, int bu
|
||||||
|
|
||||||
for (int i = 0; i < enchantCount; i++) {
|
for (int i = 0; i < enchantCount; i++) {
|
||||||
if (offset + (4 + 4) > bufSize) break;
|
if (offset + (4 + 4) > bufSize) break;
|
||||||
|
|
||||||
int type = 0;
|
int type = 0;
|
||||||
memcpy(&type, inBuf + offset, 4);
|
memcpy(&type, inBuf + offset, 4);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
|
|
||||||
int level = 0;
|
int level = 0;
|
||||||
memcpy(&level, inBuf + offset, 4);
|
memcpy(&level, inBuf + offset, 4);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
|
|
||||||
CompoundTag* ench = new CompoundTag();
|
CompoundTag* ench = new CompoundTag();
|
||||||
ench->putShort((wchar_t*)ItemInstance::TAG_ENCH_ID, static_cast<short>(type));
|
ench->putShort((wchar_t*)ItemInstance::TAG_ENCH_ID, static_cast<short>(type));
|
||||||
ench->putShort((wchar_t*)ItemInstance::TAG_ENCH_LEVEL, static_cast<byte>(level));
|
ench->putShort((wchar_t*)ItemInstance::TAG_ENCH_LEVEL, static_cast<byte>(level));
|
||||||
|
|
@ -1051,9 +1032,7 @@ void __cdecl NativeSetItemMeta(int entityId, int slot, const char *inBuf, int bu
|
||||||
{
|
{
|
||||||
CompoundTag* tag = item->getTag();
|
CompoundTag* tag = item->getTag();
|
||||||
if (tag && tag->contains(L"ench"))
|
if (tag && tag->contains(L"ench"))
|
||||||
{
|
|
||||||
tag->remove(L"ench");
|
tag->remove(L"ench");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1190,13 +1169,15 @@ void __cdecl NativeSetExhaustion(int entityId, float exhaustion)
|
||||||
fd->setExhaustion(exhaustion);
|
fd->setExhaustion(exhaustion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void __cdecl NativeSpawnParticle(int entityId, int particleId, float x, float y, float z, float offsetX, float offsetY, float offsetZ, float speed, int count)
|
void __cdecl NativeSpawnParticle(int entityId, int particleId, float x, float y, float z, float offsetX, float offsetY, float offsetZ, float speed, int count)
|
||||||
{
|
{
|
||||||
auto player = FindPlayer(entityId);
|
auto player = FindPlayer(entityId);
|
||||||
if (!player || !player->connection) return;
|
if (!player || !player->connection) return;
|
||||||
wchar_t buf[32];
|
const ParticleType* type = ParticleType::byId(particleId);
|
||||||
swprintf_s(buf, L"%d", particleId);
|
if (!type) type = ParticleType::getDefault();
|
||||||
player->connection->send(std::make_shared<LevelParticlesPacket>(std::wstring(buf), x, y, z, offsetX, offsetY, offsetZ, speed, count));
|
arrayWithLength<int> noParams = { nullptr, 0 };
|
||||||
|
player->connection->send(std::make_shared<LevelParticlesPacket>(type, false, x, y, z, offsetX, offsetY, offsetZ, speed, count, noParams));
|
||||||
}
|
}
|
||||||
|
|
||||||
int __cdecl NativeSetPassenger(int entityId, int passengerEntityId)
|
int __cdecl NativeSetPassenger(int entityId, int passengerEntityId)
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,13 @@ void ArmorStand::init()
|
||||||
registerAttributes();
|
registerAttributes();
|
||||||
defineSynchedData();
|
defineSynchedData();
|
||||||
|
|
||||||
lastHit = 0;
|
lastHit = -100LL;
|
||||||
|
standDamage = 0.0f;
|
||||||
|
hurtDir = 1;
|
||||||
disabledSlots = 0;
|
disabledSlots = 0;
|
||||||
invisible = false;
|
invisible = false;
|
||||||
isMarkerFlag = false;
|
isMarkerFlag = false;
|
||||||
|
heightOffset = 0.0f;
|
||||||
for (int i = 0; i < equipmentCount; i++)
|
for (int i = 0; i < equipmentCount; i++)
|
||||||
equipment[i] = nullptr;
|
equipment[i] = nullptr;
|
||||||
|
|
||||||
|
|
@ -56,7 +58,6 @@ void ArmorStand::init()
|
||||||
setSize(0.5f, 1.975f);
|
setSize(0.5f, 1.975f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ArmorStand::registerAttributes()
|
void ArmorStand::registerAttributes()
|
||||||
{
|
{
|
||||||
LivingEntity::registerAttributes();
|
LivingEntity::registerAttributes();
|
||||||
|
|
@ -68,8 +69,7 @@ void ArmorStand::registerAttributes()
|
||||||
void ArmorStand::defineSynchedData()
|
void ArmorStand::defineSynchedData()
|
||||||
{
|
{
|
||||||
LivingEntity::defineSynchedData();
|
LivingEntity::defineSynchedData();
|
||||||
// ArmorStand doesn't inherit from Mob, so we must register
|
|
||||||
// the custom-name fields that Mob::defineSynchedData() normally provides.
|
|
||||||
entityData->define(3, static_cast<byte>(0)); // DATA_CUSTOM_NAME_VISIBLE
|
entityData->define(3, static_cast<byte>(0)); // DATA_CUSTOM_NAME_VISIBLE
|
||||||
entityData->define(2, wstring(L"")); // DATA_CUSTOM_NAME
|
entityData->define(2, wstring(L"")); // DATA_CUSTOM_NAME
|
||||||
entityData->define(DATA_CLIENT_FLAGS, static_cast<byte>(0));
|
entityData->define(DATA_CLIENT_FLAGS, static_cast<byte>(0));
|
||||||
|
|
@ -193,13 +193,27 @@ void ArmorStand::tick()
|
||||||
{
|
{
|
||||||
float lockedRot = this->yRot;
|
float lockedRot = this->yRot;
|
||||||
LivingEntity::tick();
|
LivingEntity::tick();
|
||||||
this->yRot = lockedRot;
|
if (onGround)
|
||||||
this->yRotO = lockedRot;
|
{
|
||||||
this->yBodyRot = lockedRot;
|
BlockPos pos((int)floorf(x), (int)floorf(y) - 1, (int)floorf(z));
|
||||||
|
int blockId = level->getTile(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
if (blockId == Tile::topSnow->id)
|
||||||
|
{
|
||||||
|
int meta = level->getData(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
float snowHeight = ((meta & 0x7) + 1) * 0.125f;
|
||||||
|
moveTo(x, floorf(y) + snowHeight, z, yRot, xRot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->yRot = lockedRot;
|
||||||
|
this->yRotO = lockedRot;
|
||||||
|
this->yBodyRot = lockedRot;
|
||||||
this->yBodyRotO = lockedRot;
|
this->yBodyRotO = lockedRot;
|
||||||
this->yHeadRot = lockedRot;
|
this->yHeadRot = lockedRot;
|
||||||
this->yHeadRotO = lockedRot;
|
this->yHeadRotO = lockedRot;
|
||||||
|
|
||||||
|
if ((long long)tickCount - lastHit > 20)
|
||||||
|
standDamage = 0.0f;
|
||||||
|
|
||||||
auto syncPose = [&](int slot, Rotations& local)
|
auto syncPose = [&](int slot, Rotations& local)
|
||||||
{
|
{
|
||||||
Rotations net = entityData->getRotations(slot);
|
Rotations net = entityData->getRotations(slot);
|
||||||
|
|
@ -254,6 +268,7 @@ void ArmorStand::causeDamage(float damage)
|
||||||
h -= damage;
|
h -= damage;
|
||||||
if (h <= 0.5f)
|
if (h <= 0.5f)
|
||||||
{
|
{
|
||||||
|
spawnAtLocation(Item::armor_stand_Id, 1);
|
||||||
brokenByAnything();
|
brokenByAnything();
|
||||||
remove();
|
remove();
|
||||||
}
|
}
|
||||||
|
|
@ -266,59 +281,63 @@ void ArmorStand::causeDamage(float damage)
|
||||||
bool ArmorStand::hurt(DamageSource* source, float damage)
|
bool ArmorStand::hurt(DamageSource* source, float damage)
|
||||||
{
|
{
|
||||||
if (isInvulnerable() || level->isClientSide || removed || isMarker()) return false;
|
if (isInvulnerable() || level->isClientSide || removed || isMarker()) return false;
|
||||||
if (source != nullptr && source->getMsgId() == eEntityDamageType_Suffocate) return false;
|
|
||||||
|
|
||||||
if (source->isExplosion())
|
if (source->getMsgId() == eEntityDamageType_Suffocate) return false;
|
||||||
{
|
|
||||||
brokenByAnything();
|
|
||||||
remove();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFireDamage = source->isFire();
|
|
||||||
|
|
||||||
if (dynamic_cast<EntityDamageSource*>(source) != nullptr)
|
if (dynamic_cast<EntityDamageSource*>(source) != nullptr)
|
||||||
{
|
{
|
||||||
shared_ptr<Entity> attacker = source->getEntity();
|
shared_ptr<Entity> attacker = source->getDirectEntity();
|
||||||
if (attacker != nullptr && attacker->instanceof(eTYPE_PLAYER))
|
if (attacker && attacker->instanceof(eTYPE_PLAYER) &&
|
||||||
{
|
!dynamic_pointer_cast<Player>(attacker)->isAllowedToHurtEntity(shared_from_this()))
|
||||||
if (dynamic_pointer_cast<Player>(attacker)->abilities.instabuild)
|
return false;
|
||||||
{
|
|
||||||
level->broadcastEntityEvent(shared_from_this(), (byte)31);
|
|
||||||
remove();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFireDamage)
|
if (source->isExplosion())
|
||||||
{
|
{
|
||||||
float currentHealth = this->getHealth() - 0.15f;
|
|
||||||
this->setHealth(currentHealth);
|
|
||||||
if (currentHealth <= 0.5f)
|
|
||||||
{
|
|
||||||
brokenByAnything();
|
|
||||||
remove();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long now = (long long)tickCount;
|
|
||||||
if (now - lastHit > 5)
|
|
||||||
{
|
|
||||||
level->broadcastEntityEvent(shared_from_this(), (byte)32);
|
|
||||||
lastHit = now;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
level->broadcastEntityEvent(shared_from_this(), (byte)31);
|
|
||||||
spawnAtLocation(Item::armor_stand_Id, 1);
|
spawnAtLocation(Item::armor_stand_Id, 1);
|
||||||
brokenByAnything();
|
brokenByAnything();
|
||||||
remove();
|
remove();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dynamic_cast<EntityDamageSource*>(source) != nullptr)
|
||||||
|
{
|
||||||
|
shared_ptr<Entity> attacker = source->getEntity();
|
||||||
|
if (attacker && attacker->instanceof(eTYPE_PLAYER) &&
|
||||||
|
dynamic_pointer_cast<Player>(attacker)->abilities.instabuild)
|
||||||
|
{
|
||||||
|
level->broadcastEntityEvent(shared_from_this(), (byte)31);
|
||||||
|
remove();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source->isFire())
|
||||||
|
{
|
||||||
|
if (isInWater()) return false;
|
||||||
|
float h = getHealth() - 0.15f;
|
||||||
|
setHealth(h);
|
||||||
|
if (h <= 0.5f)
|
||||||
|
{
|
||||||
|
brokenByAnything();
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hurtDir = -hurtDir;
|
||||||
|
standDamage += damage * 10.0f;
|
||||||
|
lastHit = (long long)tickCount;
|
||||||
|
level->broadcastEntityEvent(shared_from_this(), (byte)32);
|
||||||
|
|
||||||
|
if (standDamage >= 40.0f)
|
||||||
|
{
|
||||||
|
spawnAtLocation(Item::armor_stand_Id, 1);
|
||||||
|
brokenByAnything();
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,11 @@ private:
|
||||||
bool invisible;
|
bool invisible;
|
||||||
bool isMarkerFlag;
|
bool isMarkerFlag;
|
||||||
bool noPhysics;
|
bool noPhysics;
|
||||||
|
float standDamage;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
long long lastHit;
|
long long lastHit;
|
||||||
|
int hurtDir;
|
||||||
|
|
||||||
explicit ArmorStand(Level* level);
|
explicit ArmorStand(Level* level);
|
||||||
virtual ~ArmorStand();
|
virtual ~ArmorStand();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue