Merge branch 'main' into fix/fourkit

This commit is contained in:
/home/neo 2026-04-18 11:33:49 +03:00 committed by GitHub
commit be4bfdbdcc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 2880 additions and 1574 deletions

View file

@ -0,0 +1,36 @@
#include "stdafx.h"
#include "AbstractArmorLayer.h"
#include "LivingEntityRenderer.h"
#include "HumanoidModel.h"
AbstractArmorLayer::AbstractArmorLayer(LivingEntityRenderer* renderer)
: armorModel1(nullptr),
armorModel2(nullptr),
renderer(renderer),
colorR(1.0f),
colorG(1.0f),
colorB(1.0f),
colorA(1.0f),
hasColor(false)
{
}
HumanoidModel* AbstractArmorLayer::getArmorModel(int slot) {
if (slot == 2)
return armorModel1;
return armorModel2;
}
int AbstractArmorLayer::colorsOnDamage() {
return 0;
}
void AbstractArmorLayer::resetColor() {
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
hasColor = false;
}
void AbstractArmorLayer::createArmorModels() {
// default: no-op
}

View file

@ -0,0 +1,27 @@
#pragma once
#include <memory>
using namespace std;
class LivingEntityRenderer;
class HumanoidModel;
class LivingEntity;
class AbstractArmorLayer {
public:
HumanoidModel* armorModel1;
HumanoidModel* armorModel2;
LivingEntityRenderer* renderer;
float colorR;
float colorG;
float colorB;
float colorA;
bool hasColor;
explicit AbstractArmorLayer(LivingEntityRenderer* renderer);
virtual ~AbstractArmorLayer() {}
virtual HumanoidModel* getArmorModel(int slot);
virtual void createArmorModels();
virtual int colorsOnDamage();
virtual void resetColor();
};

View file

@ -0,0 +1,70 @@
#include "stdafx.h"
#include "ArmorStandArmorModel.h"
#include "ModelPart.h"
#include "../Minecraft.World/ArmorStand.h"
static const float DEG_TO_RAD = 0.017453292f;
ArmorStandArmorModel::ArmorStandArmorModel(float scale, int texWidth, int texHeight)
: HumanoidModel(scale, 0.0f, texWidth, texHeight)
{
}
ArmorStandArmorModel::~ArmorStandArmorModel() {}
void ArmorStandArmorModel::setupAnim(float time, float r, float bob,
float yRot, float xRot, float scale,
shared_ptr<Entity> entity,
unsigned int uiBitmaskOverrideAnim)
{
if (!entity) return;
if (!entity->instanceof(eTYPE_ARMORSTAND)) return;
shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(entity);
if (!stand) return;
Rotations h = stand->getHeadPose();
Rotations b = stand->getBodyPose();
Rotations la = stand->getLeftArmPose();
Rotations ra = stand->getRightArmPose();
Rotations ll = stand->getLeftLegPose();
Rotations rl = stand->getRightLegPose();
head->xRot = DEG_TO_RAD * h.getX();
head->yRot = DEG_TO_RAD * h.getY();
head->zRot = DEG_TO_RAD * h.getZ();
head->setPos(0.0f, 1.0f, 0.0f);
body->xRot = DEG_TO_RAD * b.getX();
body->yRot = DEG_TO_RAD * b.getY();
body->zRot = DEG_TO_RAD * b.getZ();
arm0->xRot = DEG_TO_RAD * la.getX();
arm0->yRot = DEG_TO_RAD * la.getY();
arm0->zRot = DEG_TO_RAD * la.getZ();
arm1->xRot = DEG_TO_RAD * ra.getX();
arm1->yRot = DEG_TO_RAD * ra.getY();
arm1->zRot = DEG_TO_RAD * ra.getZ();
leg1->xRot = DEG_TO_RAD * ll.getX();
leg1->yRot = DEG_TO_RAD * ll.getY();
leg1->zRot = DEG_TO_RAD * ll.getZ();
leg1->setPos(1.9f, 11.0f, 0.0f);
leg0->xRot = DEG_TO_RAD * rl.getX();
leg0->yRot = DEG_TO_RAD * rl.getY();
leg0->zRot = DEG_TO_RAD * rl.getZ();
leg0->setPos(-1.9f, 11.0f, 0.0f);
ModelPart::copyModelPart(head, hair);
}

View file

@ -0,0 +1,18 @@
#pragma once
#include "HumanoidModel.h"
class Entity;
class ArmorStandArmorModel : public HumanoidModel {
public:
ArmorStandArmorModel(float scale,
int texWidth = 64,
int texHeight = 32);
virtual ~ArmorStandArmorModel();
virtual void setupAnim(float time, float r, float bob,
float yRot, float xRot, float scale,
shared_ptr<Entity> entity,
unsigned int uiBitmaskOverrideAnim = 0) override;
};

View file

@ -1,69 +1,85 @@
#include "stdafx.h" #include "stdafx.h"
#include "ModelPart.h" #include "ModelPart.h"
#include "ArmorStandModel.h" #include "ArmorStandModel.h"
#include "../Minecraft.World/ArmorStand.h" #include "../Minecraft.World/ArmorStand.h"
ArmorStandModel::ArmorStandModel() : HumanoidModel() ArmorStandModel::ArmorStandModel(float scale) : HumanoidModel(scale)
{ {
texWidth = 64; texWidth = 64;
texHeight = 64; texHeight = 64;
head = new ModelPart(this, 0, 0); head = new ModelPart(this, 0, 0);
head->addBox(-1.0F, -7.0F, -1.0F, 2, 7, 2, 0.0F); head->addBox(-1.0f, -7.0f, -1.0f, 2, 7, 2, scale);
head->setPos(0.0F, 1.0F, 0.0F); head->setPos(0.0f, 0.0f, 0.0f);
head->compile(1.0f / 16.0f); head->compile(1.0f / 16.0f);
hair = new ModelPart(this, 0, 0); hair = new ModelPart(this, 0, 0);
body = new ModelPart(this, 0, 26); body = new ModelPart(this, 0, 26);
body->addBox(-6.0F, 0.0F, -1.5F, 12, 3, 3, 0.0F); body->addBox(-6.0f, 0.0f, -1.5f, 12, 3, 3, scale);
body->setPos(0.0F, 0.0F, 0.0F); body->setPos(0.0f, 0.0f, 0.0f);
body->compile(1.0f / 16.0f); body->compile(1.0f / 16.0f);
arm0 = new ModelPart(this, 24, 0); // right
arm0->addBox(-2.0F, -2.0F, -1.0F, 2, 12, 2, 0.0F);
arm0->setPos(-5.0F, 2.0F, 0.0F);
arm0->compile(1.0f / 16.0f);
arm1 = new ModelPart(this, 32, 16); // left arm1 = new ModelPart(this, 24, 0);
arm1->addBox(0.0F, -2.0F, -1.0F, 2, 12, 2, 0.0F); arm1->addBox(-2.0f, -2.0f, -1.0f, 2, 12, 2, scale);
arm1->setPos(5.0F, 2.0F, 0.0F); arm1->setPos(-5.0f, 2.0f, 0.0f);
arm1->compile(1.0f / 16.0f); arm1->compile(1.0f / 16.0f);
leg0 = new ModelPart(this, 8, 0); // right
leg0->addBox(-1.0F, 0.0F, -1.0F, 2, 11, 2, 0.0F); arm0 = new ModelPart(this, 32, 16);
leg0->setPos(-1.9F, 12.0F, 0.0F); arm0->mirror();
arm0->addBox(0.0f, -2.0f, -1.0f, 2, 12, 2, scale);
arm0->setPos(5.0f, 2.0f, 0.0f);
arm0->compile(1.0f / 16.0f);
leg0 = new ModelPart(this, 8, 0);
leg0->addBox(-1.0f, 0.0f, -1.0f, 2, 11, 2, scale);
leg0->setPos(-1.9f, 12.0f, 0.0f);
leg0->compile(1.0f / 16.0f); leg0->compile(1.0f / 16.0f);
leg1 = new ModelPart(this, 40, 16); // left
leg1->addBox(-1.0F, 0.0F, -1.0F, 2, 11, 2, 0.0F); leg1 = new ModelPart(this, 40, 16);
leg1->setPos(1.9F, 12.0F, 0.0F); leg1->mirror();
leg1->addBox(-1.0f, 0.0f, -1.0f, 2, 11, 2, scale);
leg1->setPos(1.9f, 12.0f, 0.0f);
leg1->compile(1.0f / 16.0f); leg1->compile(1.0f / 16.0f);
//sticks
rightBodyStick = new ModelPart(this, 16, 0); rightBodyStick = new ModelPart(this, 16, 0);
rightBodyStick->addBox(-3.0F, 3.0F, -1.0F, 2, 7, 2, 0.0F); rightBodyStick->addBox(-3.0f, 3.0f, -1.0f, 2, 7, 2, scale);
rightBodyStick->setPos(0.0F, 0.0F, 0.0F); rightBodyStick->setPos(0.0f, 0.0f, 0.0f);
rightBodyStick->visible = false;
rightBodyStick->compile(1.0f / 16.0f); rightBodyStick->compile(1.0f / 16.0f);
leftBodyStick = new ModelPart(this, 48, 16); leftBodyStick = new ModelPart(this, 48, 16);
leftBodyStick->addBox(1.0F, 3.0F, -1.0F, 2, 7, 2, 0.0F); leftBodyStick->addBox(1.0f, 3.0f, -1.0f, 2, 7, 2, scale);
leftBodyStick->setPos(0.0F, 0.0F, 0.0F); leftBodyStick->setPos(0.0f, 0.0f, 0.0f);
leftBodyStick->visible = false;
leftBodyStick->compile(1.0f / 16.0f); leftBodyStick->compile(1.0f / 16.0f);
shoulderStick = new ModelPart(this, 0, 48); shoulderStick = new ModelPart(this, 0, 48);
shoulderStick->addBox(-4.0F, 10.0F, -1.0F, 8, 2, 2, 0.0F); shoulderStick->addBox(-4.0f, 10.0f, -1.0f, 8, 2, 2, scale);
shoulderStick->setPos(0.0F, 0.0F, 0.0F); shoulderStick->setPos(0.0f, 0.0f, 0.0f);
shoulderStick->compile(1.0f / 16.0f); shoulderStick->compile(1.0f / 16.0f);
basePlate = new ModelPart(this, 0, 32); basePlate = new ModelPart(this, 0, 32);
basePlate->addBox(-6.0F, 11.0F, -6.0F, 12, 1, 12, 0.0F); basePlate->mirror();
basePlate->setPos(0.0F, 12.0F, 0.0F); basePlate->addBox(-6.0f, 11.0f, -6.0f, 12, 1, 12, scale);
basePlate->setPos(0.0f, 12.0f, 0.0f);
basePlate->compile(1.0f / 16.0f); basePlate->compile(1.0f / 16.0f);
} }
void ArmorStandModel::setupPose(float hX, float hY, float hZ, void ArmorStandModel::setupPose(
float hX, float hY, float hZ,
float bX, float bY, float bZ, float bX, float bY, float bZ,
float lAX, float lAY, float lAZ, float lAX, float lAY, float lAZ,
float rAX, float rAY, float rAZ, float rAX, float rAY, float rAZ,
@ -71,45 +87,52 @@ void ArmorStandModel::setupPose(float hX, float hY, float hZ,
float rLX, float rLY, float rLZ) float rLX, float rLY, float rLZ)
{ {
head->xRot = hX; head->yRot = hY; head->zRot = hZ; head->xRot = hX; head->yRot = hY; head->zRot = hZ;
if (hair) { hair->xRot = hX; hair->yRot = hY; hair->zRot = hZ; }
body->xRot = bX; body->yRot = bY; body->zRot = bZ; body->xRot = bX; body->yRot = bY; body->zRot = bZ;
rightBodyStick->xRot = bX; rightBodyStick->yRot = bY; rightBodyStick->zRot = bZ; rightBodyStick->xRot = bX; rightBodyStick->yRot = bY; rightBodyStick->zRot = bZ;
leftBodyStick->xRot = bX; leftBodyStick->yRot = bY; leftBodyStick->zRot = bZ; leftBodyStick->xRot = bX; leftBodyStick->yRot = bY; leftBodyStick->zRot = bZ;
shoulderStick->xRot = bX; shoulderStick->yRot = bY; shoulderStick->zRot = bZ; shoulderStick->xRot = bX; shoulderStick->yRot = bY; shoulderStick->zRot = bZ;
arm1->xRot = lAX; arm1->yRot = lAY; arm1->zRot = lAZ; // left arm1->xRot = lAX; arm1->yRot = lAY; arm1->zRot = lAZ;
arm0->xRot = rAX; arm0->yRot = rAY; arm0->zRot = rAZ; // right arm0->xRot = rAX; arm0->yRot = rAY; arm0->zRot = rAZ;
leg1->xRot = lLX; leg1->yRot = lLY; leg1->zRot = lLZ; // left leg1->xRot = lLX; leg1->yRot = lLY; leg1->zRot = lLZ;
leg0->xRot = rLX; leg0->yRot = rLY; leg0->zRot = rLZ; // right leg0->xRot = rLX; leg0->yRot = rLY; leg0->zRot = rLZ;
} }
void ArmorStandModel::render(shared_ptr<Entity> entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled) void ArmorStandModel::setupAnim(float time, float r, float bob, float yRot, float xRot,
float scale, shared_ptr<Entity> entity,
unsigned int uiBitmaskOverrideAnim)
{
}
void ArmorStandModel::render(shared_ptr<Entity> entity,
float time, float r, float bob,
float yRot, float xRot,
float scale, bool usecompiled)
{ {
shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(entity); shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(entity);
if (stand) { if (stand)
{
bool armsVis = stand->isShowArms();
bool baseVis = stand->showBasePlate();
bool isSmallSt = stand->isSmall();
bool armsVisible = stand->showArms(); arm0->visible = armsVis;
arm0->visible = armsVisible; // right arm1->visible = armsVis;
arm1->visible = armsVisible; // left
rightBodyStick->visible = !isSmallSt;
// basePlate->visible = stand->showBasePlate(); leftBodyStick->visible = !isSmallSt;
shoulderStick->visible = !isSmallSt;
basePlate->visible = baseVis;
} }
HumanoidModel::render(entity, time, r, bob, yRot, xRot, scale, usecompiled); HumanoidModel::render(entity, time, r, bob, yRot, xRot, scale, usecompiled);
rightBodyStick->render(scale, usecompiled); rightBodyStick->render(scale, usecompiled);
leftBodyStick->render(scale, usecompiled); leftBodyStick->render(scale, usecompiled);
shoulderStick->render(scale, usecompiled); shoulderStick->render(scale, usecompiled);
basePlate->render(scale, usecompiled); basePlate->render(scale, usecompiled);
} }
void ArmorStandModel::setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, shared_ptr<Entity> entity, unsigned int uiBitmaskOverrideAnim)
{
}

View file

@ -1,3 +1,4 @@
#pragma once #pragma once
#include "HumanoidModel.h" #include "HumanoidModel.h"
#include "ModelPart.h" #include "ModelPart.h"
@ -5,18 +6,17 @@
class ArmorStandModel : public HumanoidModel class ArmorStandModel : public HumanoidModel
{ {
public: public:
ModelPart* rightBodyStick; ModelPart* rightBodyStick;
ModelPart* leftBodyStick; ModelPart* leftBodyStick;
ModelPart* shoulderStick; ModelPart* shoulderStick;
ModelPart* basePlate; ModelPart* basePlate;
bool showArms; ArmorStandModel(float scale = 0.0f);
bool showBasePlate; virtual ~ArmorStandModel() {}
bool isSmall;
ArmorStandModel(); virtual void setupAnim(float time, float r, float bob, float yRot, float xRot,
virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, shared_ptr<Entity> entity, unsigned int uiBitmaskOverrideAnim ) override; float scale, shared_ptr<Entity> entity,
unsigned int uiBitmaskOverrideAnim = 0) override;
void setupPose(float hX, float hY, float hZ, void setupPose(float hX, float hY, float hZ,
float bX, float bY, float bZ, float bX, float bY, float bZ,

View file

@ -1,59 +1,97 @@
#include "stdafx.h" #include "stdafx.h"
#include "ArmorStandRenderer.h" #include "ArmorStandRenderer.h"
#include "Textures.h"
#include "HumanoidModel.h"
#include "ArmorStandModel.h" #include "ArmorStandModel.h"
#include "..\Minecraft.World\ArmorStand.h" #include "ArmorStandArmorModel.h"
#include "HumanoidModel.h"
#include "ItemInHandLayer.h"
#include "CustomHeadLayer.h"
class ArmorStandArmorModel : public HumanoidModel { #include "Textures.h"
public: #include "HumanoidMobRenderer.h"
ArmorStandArmorModel(float scale) : HumanoidModel(scale) {} #include "../Minecraft.World/ArmorStand.h"
#include "../Minecraft.World/ArmorItem.h"
virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, shared_ptr<Entity> entity, unsigned int uiBitmaskOverrideAnim = 0) override {
}
};
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(TN_MOB_ARMORSTAND); ResourceLocation ArmorStandRenderer::LOC_ARMOR_STAND =
ResourceLocation(TN_MOB_ARMORSTAND);
ArmorStandRenderer::ArmorStandRenderer()
: HumanoidMobRenderer(new ArmorStandModel(), 0.0f, 1.0f)
ArmorStandRenderer::ArmorStandArmorLayer::ArmorStandArmorLayer(
LivingEntityRenderer* renderer)
: HumanoidArmorLayer(renderer)
{ {
createArmorParts();
delete armorModel1;
delete armorModel2;
armorModel1 = new ArmorStandArmorModel(0.5f);
armorModel2 = new ArmorStandArmorModel(1.0f);
} }
void ArmorStandRenderer::ArmorStandArmorLayer::createArmorModels()
{
delete armorModel1;
delete armorModel2;
armorModel1 = new ArmorStandArmorModel(0.5f);
armorModel2 = new ArmorStandArmorModel(1.0f);
}
ArmorStandRenderer::ArmorStandRenderer()
: LivingEntityRenderer(new ArmorStandModel(0.0f), 0.0f)
{
addLayer(new ArmorStandArmorLayer(this));
addLayer(new ItemInHandLayer(this));
ArmorStandModel* m = static_cast<ArmorStandModel*>(getModel());
addLayer(new CustomHeadLayer(m->head));
}
ArmorStandRenderer::~ArmorStandRenderer()
{
}
ResourceLocation* ArmorStandRenderer::getTextureLocation(shared_ptr<Entity> entity) ResourceLocation* ArmorStandRenderer::getTextureLocation(shared_ptr<Entity> entity)
{ {
return &LOC_ARMOR_STAND; return &LOC_ARMOR_STAND;
} }
void ArmorStandRenderer::createArmorParts() bool ArmorStandRenderer::shouldShowName(shared_ptr<LivingEntity> entity)
{ {
armorParts1 = new ArmorStandArmorModel(1.0f); if (!entity) return false;
armorParts2 = new ArmorStandArmorModel(0.5f); return entity->isCustomNameVisible();
} }
void ArmorStandRenderer::render(shared_ptr<Entity> entity, double x, double y, double z, float rot, float a) void ArmorStandRenderer::setupRotations(shared_ptr<LivingEntity> mob,
float bob, float bodyRot, float a)
{ {
HumanoidMobRenderer::render(entity, x, y, z, rot, a);
glRotatef(180.0f - bodyRot, 0.0f, 1.0f, 0.0f);
} }
void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob, float wp, float ws, float bob, void ArmorStandRenderer::render(shared_ptr<Entity> entity,
float headRotMinusBodyRot, float headRotx, float scale) double x, double y, double z,
float rot, float a)
{ {
LivingEntityRenderer::render(entity, x, y, z, rot, a);
}
void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRotMinusBodyRot,
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;
ArmorStandModel *m = static_cast<ArmorStandModel *>(model); ArmorStandModel* m = static_cast<ArmorStandModel*>(getModel());
if (!m) return; if (!m) return;
@ -66,46 +104,118 @@ void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob, float wp, flo
m->setupPose( m->setupPose(
h.x * DEG_TO_RAD, h.y * DEG_TO_RAD, h.z * DEG_TO_RAD, h.getX() * DEG_TO_RAD, h.getY() * DEG_TO_RAD, h.getZ() * DEG_TO_RAD,
b.x * DEG_TO_RAD, b.y * DEG_TO_RAD, b.z * DEG_TO_RAD, b.getX() * DEG_TO_RAD, b.getY() * DEG_TO_RAD, b.getZ() * DEG_TO_RAD,
la.x * DEG_TO_RAD, la.y * DEG_TO_RAD, la.z * DEG_TO_RAD, la.getX() * DEG_TO_RAD, la.getY() * DEG_TO_RAD, la.getZ() * DEG_TO_RAD,
ra.x * DEG_TO_RAD, ra.y * DEG_TO_RAD, ra.z * DEG_TO_RAD, ra.getX() * DEG_TO_RAD, ra.getY() * DEG_TO_RAD, ra.getZ() * DEG_TO_RAD,
ll.x * DEG_TO_RAD, ll.y * DEG_TO_RAD, ll.z * DEG_TO_RAD, ll.getX() * DEG_TO_RAD, ll.getY() * DEG_TO_RAD, ll.getZ() * DEG_TO_RAD,
rl.x * DEG_TO_RAD, rl.y * DEG_TO_RAD, rl.z * DEG_TO_RAD rl.getX() * DEG_TO_RAD, rl.getY() * DEG_TO_RAD, rl.getZ() * DEG_TO_RAD
); );
ArmorStandArmorLayer* al = getArmorLayer();
HumanoidModel *a1 = static_cast<HumanoidModel*>(armorParts1); if (al)
if (a1) { {
a1->head->xRot = h.x * DEG_TO_RAD; a1->head->yRot = h.y * DEG_TO_RAD; a1->head->zRot = h.z * DEG_TO_RAD; auto applyPose = [&](HumanoidModel* am)
if (a1->hair) { a1->hair->xRot = h.x * DEG_TO_RAD; a1->hair->yRot = h.y * DEG_TO_RAD; a1->hair->zRot = h.z * DEG_TO_RAD; } {
if (!am) return;
a1->body->xRot = b.x * DEG_TO_RAD; a1->body->yRot = b.y * DEG_TO_RAD; a1->body->zRot = b.z * DEG_TO_RAD;
a1->arm0->xRot = ra.x * DEG_TO_RAD; a1->arm0->yRot = ra.y * DEG_TO_RAD; a1->arm0->zRot = ra.z * DEG_TO_RAD; // right am->head->xRot = h.getX() * DEG_TO_RAD;
a1->arm1->xRot = la.x * DEG_TO_RAD; a1->arm1->yRot = la.y * DEG_TO_RAD; a1->arm1->zRot = la.z * DEG_TO_RAD; // left am->head->yRot = h.getY() * DEG_TO_RAD;
am->head->zRot = h.getZ() * DEG_TO_RAD;
a1->leg0->xRot = rl.x * DEG_TO_RAD; a1->leg0->yRot = rl.y * DEG_TO_RAD; a1->leg0->zRot = rl.z * DEG_TO_RAD; // right if (am->hair) {
a1->leg1->xRot = ll.x * DEG_TO_RAD; a1->leg1->yRot = ll.y * DEG_TO_RAD; a1->leg1->zRot = ll.z * DEG_TO_RAD; // left am->hair->xRot = h.getX() * DEG_TO_RAD;
} am->hair->yRot = h.getY() * DEG_TO_RAD;
am->hair->zRot = h.getZ() * DEG_TO_RAD;
HumanoidModel *a2 = static_cast<HumanoidModel*>(armorParts2);
if (a2) {
a2->head->xRot = h.x * DEG_TO_RAD; a2->head->yRot = h.y * DEG_TO_RAD; a2->head->zRot = h.z * DEG_TO_RAD;
if (a2->hair) { a2->hair->xRot = h.x * DEG_TO_RAD; a2->hair->yRot = h.y * DEG_TO_RAD; a2->hair->zRot = h.z * DEG_TO_RAD; }
a2->body->xRot = b.x * DEG_TO_RAD; a2->body->yRot = b.y * DEG_TO_RAD; a2->body->zRot = b.z * DEG_TO_RAD;
a2->arm0->xRot = ra.x * DEG_TO_RAD; a2->arm0->yRot = ra.y * DEG_TO_RAD; a2->arm0->zRot = ra.z * DEG_TO_RAD;
a2->arm1->xRot = la.x * DEG_TO_RAD; a2->arm1->yRot = la.y * DEG_TO_RAD; a2->arm1->zRot = la.z * DEG_TO_RAD;
a2->leg0->xRot = rl.x * DEG_TO_RAD; a2->leg0->yRot = rl.y * DEG_TO_RAD; a2->leg0->zRot = rl.z * DEG_TO_RAD;
a2->leg1->xRot = ll.x * DEG_TO_RAD; a2->leg1->yRot = ll.y * DEG_TO_RAD; a2->leg1->zRot = ll.z * DEG_TO_RAD;
} }
HumanoidMobRenderer::renderModel(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale); 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*>(al->armorModel1));
applyPose(static_cast<HumanoidModel*>(al->armorModel2));
} }
LivingEntityRenderer::renderModel(mob, wp, ws, bob,
headRotMinusBodyRot, headRotx, scale);
for (size_t i = 0; i < renderLayers.size(); ++i) {
if (renderLayers[i]) {
renderLayers[i]->render(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale, true);
}
}
}
int ArmorStandRenderer::prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a)
{
if (!armorLayer) return -1;
shared_ptr<ItemInstance> itemInstance = mob->getArmor(3 - layer);
if (itemInstance != nullptr)
{
Item *item = itemInstance->getItem();
ArmorItem *armorItem = dynamic_cast<ArmorItem *>(item);
if (armorItem != nullptr)
{
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;
}
}
return -1;
}

View file

@ -1,24 +1,54 @@
#pragma once #pragma once
#include "HumanoidMobRenderer.h" #include "LivingEntityRenderer.h"
#include "ArmorStandModel.h" #include "HumanoidArmorLayer.h"
#include "..\Minecraft.World\ArmorStand.h" #include "ResourceLocation.h"
class ArmorStandRenderer : public HumanoidMobRenderer #include <vector>
{
private:
static ResourceLocation LOC_ARMOR_STAND;
class ArmorStandModel;
class LivingEntity;
class Entity;
class RenderLayer;
class ArmorStandRenderer : public LivingEntityRenderer {
public: public:
ArmorStandRenderer(); class ArmorStandArmorLayer : public HumanoidArmorLayer {
virtual ~ArmorStandRenderer() {} public:
virtual void render(shared_ptr<Entity> entity, double x, double y, double z, float rot, float a) override; explicit ArmorStandArmorLayer(LivingEntityRenderer* renderer);
virtual ResourceLocation *getTextureLocation(shared_ptr<Entity> entity) override; virtual ~ArmorStandArmorLayer() {}
virtual void createArmorModels() override;
};
protected: protected:
std::vector<RenderLayer*> renderLayers;
ArmorStandArmorLayer* armorLayer;
virtual void createArmorParts() override; public:
void addLayer(RenderLayer* layer) {
renderLayers.push_back(layer);
}
void addLayer(ArmorStandArmorLayer* layer) {
armorLayer = layer;
}
ArmorStandArmorLayer* getArmorLayer() {
return armorLayer;
}
static ResourceLocation LOC_ARMOR_STAND;
virtual void renderModel(shared_ptr<LivingEntity> mob, float wp, float ws, float bob, ArmorStandRenderer();
float headRotMinusBodyRot, float headRotx, float scale) override; virtual ~ArmorStandRenderer();
virtual ResourceLocation* getTextureLocation(shared_ptr<Entity> entity) 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 render(shared_ptr<Entity> entity,
double x, double y, double z,
float rot, float a) override;
virtual void renderModel(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRotMinusBodyRot,
float headRotx, float scale) override;
virtual int prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a) override;
}; };

View file

@ -4300,8 +4300,10 @@ void ClientConnection::handleSetPlayerTeamPacket(shared_ptr<SetPlayerTeamPacket>
void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet) void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet)
{ {
wstring particleName = packet->getName(); const ParticleType* type = packet->getType();
ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)Integer::parseInt(particleName); if (type == nullptr) return;
ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)type->getId();
for (int i = 0; i < packet->getCount(); i++) for (int i = 0; i < packet->getCount(); i++)
{ {

View file

@ -242,6 +242,34 @@ CMinecraftApp::CMinecraftApp()
} }
void CMinecraftApp::GetSkinAdjustments(_SkinAdjustments* out,
unsigned int skinId)
{
_SkinAdjustments adj;
EnterCriticalSection(&csAdditionalSkinBoxes);
if (!m_SkinAdjustmentsMap.empty())
{
auto it = m_SkinAdjustmentsMap.find(skinId);
if (it != m_SkinAdjustmentsMap.end())
adj = it->second;
}
LeaveCriticalSection(&csAdditionalSkinBoxes);
*out = adj;
}
void CMinecraftApp::SetSkinAdjustments(unsigned int skinId,
const _SkinAdjustments& adj)
{
EnterCriticalSection(&csAdditionalSkinBoxes);
m_SkinAdjustmentsMap[skinId] = adj;
LeaveCriticalSection(&csAdditionalSkinBoxes);
}
void CMinecraftApp::DebugPrintf(const char *szFormat, ...) void CMinecraftApp::DebugPrintf(const char *szFormat, ...)
{ {

View file

@ -24,6 +24,8 @@ using namespace std;
#include "../ArchiveFile.h" #include "../ArchiveFile.h"
#include "lce_filesystem/FolderFile.h" #include "lce_filesystem/FolderFile.h"
typedef struct _JoinFromInviteData typedef struct _JoinFromInviteData
{ {
DWORD dwUserIndex; // dwUserIndex DWORD dwUserIndex; // dwUserIndex
@ -53,6 +55,7 @@ class Model;
class ModelPart; class ModelPart;
class StringTable; class StringTable;
class Merchant; class Merchant;
struct _SkinAdjustments;
class CMinecraftAudio; class CMinecraftAudio;
@ -64,7 +67,7 @@ class CMinecraftApp
{ {
private: private:
static int s_iHTMLFontSizesA[eHTMLSize_COUNT]; static int s_iHTMLFontSizesA[eHTMLSize_COUNT];
unordered_map<unsigned int, _SkinAdjustments> m_SkinAdjustmentsMap;
public: public:
CMinecraftApp(); CMinecraftApp();
@ -82,6 +85,8 @@ public:
// storing credits text from the DLC // storing credits text from the DLC
std::vector <wstring > m_vCreditText; // hold the credit text lines so we can avoid duplicating them std::vector <wstring > m_vCreditText; // hold the credit text lines so we can avoid duplicating them
void GetSkinAdjustments(_SkinAdjustments* out,unsigned int skinId);
void SetSkinAdjustments(unsigned int skinId, const _SkinAdjustments& adj);
// In builds prior to TU5, the size of the GAME_SETTINGS struct was 204 bytes. We added a few new values to the internal struct in TU5, and even though we // In builds prior to TU5, the size of the GAME_SETTINGS struct was 204 bytes. We added a few new values to the internal struct in TU5, and even though we
// changed the size of the ucUnused array to be decreased by the size of the values we added, the packing of the struct has introduced some extra // changed the size of the ucUnused array to be decreased by the size of the values we added, the packing of the struct has introduced some extra

View file

@ -15,7 +15,11 @@ DLCSkinFile::DLCSkinFile(const wstring &path) : DLCFile(DLCManager::e_DLCType_Sk
m_bIsFree = false; m_bIsFree = false;
m_uiAnimOverrideBitmask=0L; m_uiAnimOverrideBitmask=0L;
} }
void DLCSkinFile::getSkinAdjustments(_SkinAdjustments* adj)
{
memcpy(adj, &m_skinAdjustments, sizeof(_SkinAdjustments));
}
void DLCSkinFile::addData(PBYTE pbData, DWORD dwBytes) void DLCSkinFile::addData(PBYTE pbData, DWORD dwBytes)
{ {
app.AddMemoryTextureFile(m_path,pbData,dwBytes); app.AddMemoryTextureFile(m_path,pbData,dwBytes);

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "DLCFile.h" #include "DLCFile.h"
#include "../../../Minecraft.Client/HumanoidModel.h" #include "../../../Minecraft.Client/HumanoidModel.h"
#include "../../../Minecraft.World/Entity.h"
class DLCSkinFile : public DLCFile class DLCSkinFile : public DLCFile
{ {
@ -12,11 +13,12 @@ private:
unsigned int m_uiAnimOverrideBitmask; unsigned int m_uiAnimOverrideBitmask;
bool m_bIsFree; bool m_bIsFree;
vector<SKIN_BOX *> m_AdditionalBoxes; vector<SKIN_BOX *> m_AdditionalBoxes;
_SkinAdjustments m_skinAdjustments;
public: public:
DLCSkinFile(const wstring &path); DLCSkinFile(const wstring &path);
void getSkinAdjustments(_SkinAdjustments* adj);
void addData(PBYTE pbData, DWORD dwBytes) override; void addData(PBYTE pbData, DWORD dwBytes) override;
void addParameter(DLCManager::EDLCParameterType type, const wstring &value) override; void addParameter(DLCManager::EDLCParameterType type, const wstring &value) override;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,78 @@
#include "stdafx.h"
#include "CustomHeadLayer.h"
#include "ModelPart.h"
#include "../Minecraft.World/ItemInstance.h"
#include "../Minecraft.World/Item.h"
#include "../Minecraft.World/Tile.h"
#include "../Minecraft.World/LivingEntity.h"
CustomHeadLayer::CustomHeadLayer(ModelPart* headPart)
: headPart(headPart)
{
}
int CustomHeadLayer::colorsOnDamage() {
return 1;
}
void CustomHeadLayer::render(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRot, float headRotX,
float scale, bool useCompiled)
{
ItemInstanceArray slots = mob->getEquipmentSlots();
if (slots.length < 5) return;
shared_ptr<ItemInstance> helmet = slots[4];
if (!helmet) return;
Item* item = helmet->getItem();
if (!item) return;
bool hasHatLayer = false;
if (mob->instanceof(eTYPE_PLAYER)) {
_SkinAdjustments adj;
mob->getSkinAdjustments(&adj);
hasHatLayer = (adj.data[0] & 0x100) != 0;
}
glPushMatrix();
headPart->translateTo(0.0625f);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
int itemId = item->id;
if (itemId == Tile::skull_Id) {
glScalef(1.1875f, -1.1875f, -1.1875f);
if (hasHatLayer)
glTranslatef(0.0f, 0.0625f, 0.0f);
} else if (itemId < 0x100) {
glTranslatef(0.0f, -0.25f, 0.0f);
glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
glScalef(0.625f, -0.625f, -0.625f);
if (hasHatLayer)
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();
}

View file

@ -0,0 +1,20 @@
#pragma once
#include "RenderLayer.h"
class ModelPart;
class LivingEntity;
class CustomHeadLayer : public RenderLayer {
public:
ModelPart* headPart;
explicit CustomHeadLayer(ModelPart* headPart);
virtual ~CustomHeadLayer() {}
virtual int colorsOnDamage() override;
virtual void render(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRot, float headRotX,
float scale, bool useCompiled) override;
};

View file

@ -180,3 +180,7 @@ void GameMode::handleDebugOptions(unsigned int uiVal, shared_ptr<Player> player)
{ {
player->SetDebugOptions(uiVal); player->SetDebugOptions(uiVal);
} }
bool GameMode::isSpectator()
{
return gameType == GameType::SPECTATOR;
}

View file

@ -0,0 +1,47 @@
#include "stdafx.h"
#include "HumanoidArmorLayer.h"
#include "HumanoidModel.h"
#include "ModelPart.h"
HumanoidArmorLayer::HumanoidArmorLayer(LivingEntityRenderer* renderer)
: AbstractArmorLayer(renderer)
{
armorModel1 = new HumanoidModel(0.5f);
armorModel2 = new HumanoidModel(1.0f);
}
void HumanoidArmorLayer::createArmorModels() {
delete armorModel1;
delete armorModel2;
armorModel1 = new HumanoidModel(0.5f);
armorModel2 = new HumanoidModel(1.0f);
}
void HumanoidArmorLayer::setPartVisibility(HumanoidModel* m, unsigned int slot) {
m->setAllVisible(false);
switch (slot) {
case 0: break;
case 1:
m->leg0->visible = true;
m->leg1->visible = true;
break;
case 2:
m->body->visible = true;
m->leg0->visible = true;
m->leg1->visible = true;
break;
case 3:
m->arm1->visible = true;
m->arm0->visible = true;
break;
case 4:
m->head->visible = true;
if (m->hair) m->hair->visible = true;
break;
default: break;
}
}

View file

@ -0,0 +1,14 @@
#pragma once
#include "AbstractArmorLayer.h"
class LivingEntityRenderer;
class LivingEntity;
class HumanoidArmorLayer : public AbstractArmorLayer {
public:
explicit HumanoidArmorLayer(LivingEntityRenderer* renderer);
virtual ~HumanoidArmorLayer() {}
virtual void createArmorModels() override;
virtual void setPartVisibility(HumanoidModel* model, unsigned int slot);
};

View file

@ -968,3 +968,38 @@ void HumanoidModel::render(HumanoidModel *model, float scale, bool usecompiled)
if (pants1) if (pants1)
pants1->render(scale, usecompiled,(m_uiAnimOverrideBitmask&(1<<eAnim_DisableRenderPants1))>0); pants1->render(scale, usecompiled,(m_uiAnimOverrideBitmask&(1<<eAnim_DisableRenderPants1))>0);
} }
void HumanoidModel::setAllVisible(bool v) {
head->visible = v;
hair->visible = v;
body->visible = v;
arm1->visible = v;
arm0->visible = v;
leg0->visible = v;
leg1->visible = v;
}
void HumanoidModel::translateToHandItem(float scale) {
arm1->translateTo(scale);
}
bool HumanoidModel::IsBodyPartDisabled(animbits bit) {
return (m_uiAnimOverrideBitmask & (1u << bit)) != 0;
}
void HumanoidModel::copyPropertiesFrom(HumanoidModel* other) {
if (!other) return;
idle = other->idle;
sneaking = other->sneaking;
bowAndArrow = other->bowAndArrow;
eating = other->eating;
eating_t = other->eating_t;
eating_swing = other->eating_swing;
holdingLeftHand = other->holdingLeftHand;
holdingRightHand = other->holdingRightHand;
m_uiAnimOverrideBitmask = other->m_uiAnimOverrideBitmask;
m_fYOffset = other->m_fYOffset;
}

View file

@ -1,35 +1,32 @@
#pragma once #pragma once
#include "Model.h" #include "Model.h"
class HumanoidModel : public Model class HumanoidModel : public Model
{ {
public: public:
ModelPart *head, *hair, *body, *jacket, *arm0, *sleeve0, *arm1, *sleeve1, *leg0, *pants0, *leg1, *pants1, *ear, *cloak; ModelPart *head, *hair, *body, *jacket, *arm0, *sleeve0, *arm1, *sleeve1, *leg0, *pants0, *leg1, *pants1, *ear, *cloak;
//ModelPart *hat;
int holdingLeftHand; int holdingLeftHand;
int holdingRightHand; int holdingRightHand;
bool idle; bool idle;
bool sneaking; bool sneaking;
bool bowAndArrow; bool bowAndArrow;
bool eating; // 4J added bool eating;
float eating_t; // 4J added float eating_t;
float eating_swing; // 4J added float eating_swing;
unsigned int m_uiAnimOverrideBitmask; // 4J added unsigned int m_uiAnimOverrideBitmask;
float m_fYOffset; // 4J added float m_fYOffset;
enum animbits enum animbits
{ {
eAnim_ArmsDown = 0, eAnim_ArmsDown = 0,
eAnim_ArmsOutFront, eAnim_ArmsOutFront,
eAnim_NoLegAnim, eAnim_NoLegAnim,
eAnim_HasIdle, eAnim_HasIdle,
eAnim_ForceAnim, // Claptrap looks bad if the user turns off custom skin anim eAnim_ForceAnim,
// 4J-PB - DaveK wants Fish characters to move both legs in the same way
eAnim_SingleLegs, eAnim_SingleLegs,
eAnim_SingleArms, eAnim_SingleArms,
eAnim_StatueOfLiberty, // Dr Who Weeping Angel eAnim_StatueOfLiberty,
eAnim_DontRenderArmour, // Dr Who Daleks eAnim_DontRenderArmour,
eAnim_NoBobbing, // Dr Who Daleks eAnim_NoBobbing,
eAnim_DisableRenderHead, eAnim_DisableRenderHead,
eAnim_DisableRenderArm0, eAnim_DisableRenderArm0,
eAnim_DisableRenderArm1, eAnim_DisableRenderArm1,
@ -45,7 +42,8 @@ public:
eAnim_DisableRenderPants1 eAnim_DisableRenderPants1
}; };
static const unsigned int m_staticBitmaskIgnorePlayerCustomAnimSetting= (1<<HumanoidModel::eAnim_ForceAnim) | static const unsigned int m_staticBitmaskIgnorePlayerCustomAnimSetting =
(1 << HumanoidModel::eAnim_ForceAnim) |
(1 << HumanoidModel::eAnim_DisableRenderArm0) | (1 << HumanoidModel::eAnim_DisableRenderArm0) |
(1 << HumanoidModel::eAnim_DisableRenderArm1) | (1 << HumanoidModel::eAnim_DisableRenderArm1) |
(1 << HumanoidModel::eAnim_DisableRenderTorso) | (1 << HumanoidModel::eAnim_DisableRenderTorso) |
@ -58,21 +56,38 @@ public:
(1 << HumanoidModel::eAnim_DisableRenderPants0) | (1 << HumanoidModel::eAnim_DisableRenderPants0) |
(1 << HumanoidModel::eAnim_DisableRenderPants1); (1 << HumanoidModel::eAnim_DisableRenderPants1);
void _init(float g, float yOffset, int texWidth, int texHeight,
bool slimHands, bool mirror, bool force32);
void _init(float g, float yOffset, int texWidth, int texHeight, bool slimHands, bool mirror, bool force32); // 4J added
HumanoidModel(); HumanoidModel();
HumanoidModel(float g); HumanoidModel(float g);
HumanoidModel(float g, float yOffset, int texWidth, int texHeight); HumanoidModel(float g, float yOffset, int texWidth, int texHeight);
HumanoidModel(float g, float yOffset, int texWidth, int texHeight, bool slimHands); HumanoidModel(float g, float yOffset, int texWidth, int texHeight, bool slimHands);
HumanoidModel(float g, float yOffset, int texWidth, int texHeight, bool slimHands, bool mirror); HumanoidModel(float g, float yOffset, int texWidth, int texHeight, bool slimHands, bool mirror);
HumanoidModel(float g, float yOffset, int texWidth, int texHeight, bool slimHands, bool mirror, bool force32); HumanoidModel(float g, float yOffset, int texWidth, int texHeight, bool slimHands, bool mirror, bool force32);
virtual void render(shared_ptr<Entity> entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled);
virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, shared_ptr<Entity> entity, unsigned int uiBitmaskOverrideAnim = 0); virtual void render(shared_ptr<Entity> entity, float time, float r, float bob,
float yRot, float xRot, float scale, bool usecompiled);
virtual void setupAnim(float time, float r, float bob, float yRot, float xRot,
float scale, shared_ptr<Entity> entity,
unsigned int uiBitmaskOverrideAnim = 0);
void renderHair(float scale, bool usecompiled); void renderHair(float scale, bool usecompiled);
void renderEars(float scale, bool usecompiled); void renderEars(float scale, bool usecompiled);
void renderCloak(float scale, bool usecompiled); void renderCloak(float scale, bool usecompiled);
void render(HumanoidModel* model, float scale, bool usecompiled); void render(HumanoidModel* model, float scale, bool usecompiled);
// Add new bits to models
ModelPart* AddOrRetrievePart(SKIN_BOX* pBox); ModelPart* AddOrRetrievePart(SKIN_BOX* pBox);
void setAllVisible(bool visible);
void translateToHandItem(float scale);
void copyPropertiesFrom(HumanoidModel* other);
bool IsBodyPartDisabled(animbits bit);
}; };

View file

@ -0,0 +1,63 @@
#include "stdafx.h"
#include "ItemInHandLayer.h"
#include "LivingEntityRenderer.h"
#include "ModelPart.h"
#include "../Minecraft.World/ItemInstance.h"
#include "../Minecraft.World/Item.h"
#include "../Minecraft.World/LivingEntity.h"
#include "../Minecraft.World/Tile.h"
ItemInHandLayer::ItemInHandLayer(LivingEntityRenderer* renderer)
: renderer(renderer)
{
}
int ItemInHandLayer::colorsOnDamage() {
return 0;
}
void ItemInHandLayer::render(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRot, float headRotX,
float scale, bool useCompiled)
{
ItemInstanceArray slots = mob->getEquipmentSlots();
if (slots.length == 0) return;
shared_ptr<ItemInstance> item = slots[0];
if (!item) return;
Item* heldItem = item->getItem();
if (!heldItem) return;
glPushMatrix();
glTranslatef(-0.0625f, 0.4375f, 0.0625f);
int itemId = heldItem->id;
if (itemId > 0 && itemId < 0x100) {
if (Tile::tiles[itemId]) {
int shape = Tile::tiles[itemId]->getRenderShape();
if (shape == Tile::SHAPE_BLOCK) {
glTranslatef(0.0f, 0.1875f, -0.3125f);
glRotatef(20.0f, 1.0f, 0.0f, 0.0f);
glRotatef(45.0f, 0.0f, 1.0f, 0.0f);
glScalef(-0.375f, -0.375f, 0.375f);
}
}
} else {
glTranslatef(0.25f, 0.1875f, -0.1875f);
glScalef(0.375f, 0.375f, 0.375f);
glRotatef(60.0f, 0.0f, 0.0f, 1.0f);
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
glRotatef(20.0f, 0.0f, 0.0f, 1.0f);
}
// TODO: renderItem
glPopMatrix();
}

View file

@ -0,0 +1,20 @@
#pragma once
#include "RenderLayer.h"
class LivingEntityRenderer;
class LivingEntity;
class ItemInHandLayer : public RenderLayer {
public:
LivingEntityRenderer* renderer;
explicit ItemInHandLayer(LivingEntityRenderer* renderer);
virtual ~ItemInHandLayer() {}
virtual int colorsOnDamage() override;
virtual void render(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRot, float headRotX,
float scale, bool useCompiled) override;
};

View file

@ -157,7 +157,7 @@ void LocalPlayer::serverAiStep()
// mapPlayerChunk(8); // mapPlayerChunk(8);
} }
bool LocalPlayer::isEffectiveAi() bool LocalPlayer::isEffectiveAi() const
{ {
return true; return true;
} }

View file

@ -95,7 +95,7 @@ public:
virtual void serverAiStep(); virtual void serverAiStep();
protected: protected:
bool isEffectiveAi(); bool isEffectiveAi() const;
public: public:
virtual void aiStep(); virtual void aiStep();

View file

@ -321,3 +321,14 @@ void ModelPart::mimic(ModelPart *o)
yRot = o->yRot; yRot = o->yRot;
zRot = o->zRot; zRot = o->zRot;
} }
void ModelPart::copyModelPart(ModelPart* src, ModelPart* dst) {
if (!src || !dst) return;
dst->x = src->x;
dst->y = src->y;
dst->z = src->z;
dst->xRot = src->xRot;
dst->yRot = src->yRot;
dst->zRot = src->zRot;
}

View file

@ -60,4 +60,5 @@ public:
void compile(float scale); void compile(float scale);
int getfU() {return xTexOffs;} int getfU() {return xTexOffs;}
int getfV() {return yTexOffs;} int getfV() {return yTexOffs;}
static void copyModelPart(ModelPart* src, ModelPart* dst);
}; };

View file

@ -0,0 +1,39 @@
#include "stdafx.h"
#include "ParticleType.h"
ParticleType::ParticleType(const std::string& name, int id, bool overrideLimiter, int paramCount)
{
this->name = name;
this->id = id;
this->overrideLimiter = overrideLimiter;
this->paramCount = paramCount;
}
int ParticleType::getId() const
{
return id;
}
bool ParticleType::getOverrideLimiter() const
{
return overrideLimiter;
}
int ParticleType::getParamCount() const
{
return paramCount;
}
const ParticleType* ParticleType::getDefault()
{
return nullptr;
}
const ParticleType* ParticleType::byId(int searchId)
{
return nullptr;
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <string>
class ParticleType
{
private:
std::string name;
int id;
bool overrideLimiter;
int paramCount;
public:
ParticleType(const std::string& name, int id, bool overrideLimiter, int paramCount);
int getId() const;
bool getOverrideLimiter() const;
int getParamCount() const;
static const ParticleType* byId(int id);
static const ParticleType* getDefault();
};

View file

@ -0,0 +1,14 @@
#pragma once
#include <memory>
using namespace std;
class LivingEntity;
class RenderLayer {
public:
virtual ~RenderLayer() {}
virtual int colorsOnDamage() = 0;
virtual void render(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRot, float headRotX,
float scale, bool useCompiled) = 0;
};

View file

@ -1283,22 +1283,6 @@ PortalForcer *ServerLevel::getPortalForcer()
return portalForcer; return portalForcer;
} }
void ServerLevel::sendParticles(const wstring &name, double x, double y, double z, int count)
{
sendParticles(name, x + 0.5f, y + 0.5f, z + 0.5f, count, 0.5f, 0.5f, 0.5f, 0.02f);
}
void ServerLevel::sendParticles(const wstring &name, double x, double y, double z, int count, double xDist, double yDist, double zDist, double speed)
{
shared_ptr<Packet> packet = std::make_shared<LevelParticlesPacket>( name, static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(xDist), static_cast<float>(yDist), static_cast<float>(zDist), static_cast<float>(speed), count );
for(auto& it : players)
{
shared_ptr<ServerPlayer> player = dynamic_pointer_cast<ServerPlayer>(it);
player->connection->send(packet);
}
}
// 4J Stu - Sometimes we want to update tiles on the server from the main thread (eg SignTileEntity when string verify returns) // 4J Stu - Sometimes we want to update tiles on the server from the main thread (eg SignTileEntity when string verify returns)
void ServerLevel::queueSendTileUpdate(int x, int y, int z) void ServerLevel::queueSendTileUpdate(int x, int y, int z)
{ {
@ -1632,3 +1616,34 @@ void ServerLevel::flagEntitiesToBeRemoved(unsigned int *flags, bool *removedFoun
chunkMap->flagEntitiesToBeRemoved(flags, removedFound); chunkMap->flagEntitiesToBeRemoved(flags, removedFound);
} }
} }
void ServerLevel::sendParticles(const ParticleType* type, bool longDistance, double x, double y, double z, int count, double dx, double dy, double dz, double speed, arrayWithLength<int> data)
{
auto packet = make_shared<LevelParticlesPacket>(
type,
longDistance,
(float)x, (float)y, (float)z,
(float)dx, (float)dy, (float)dz,
(float)speed,
count,
data
);
for (auto const& p : players)
{
shared_ptr<ServerPlayer> player = dynamic_pointer_cast<ServerPlayer>(p);
if (player != nullptr && player->connection != nullptr)
{
double distSqr = player->distanceToSqr(x, y, z);
if (distSqr <= 256.0 || (longDistance && distSqr <= 65536.0))
{
player->connection->send(packet);
}
}
}
}
void ServerLevel::sendParticles(const ParticleType* type, double x, double y, double z, int count, double dx, double dy, double dz, double speed, arrayWithLength<int> data)
{
this->sendParticles(type, false, x, y, z, count, dx, dy, dz, speed, data);
}

View file

@ -1,11 +1,14 @@
#pragma once #pragma once
#include "../Minecraft.World/net.minecraft.world.level.h" #include "../Minecraft.World/net.minecraft.world.level.h"
#include "../Minecraft.World/JavaIntHash.h" #include "../Minecraft.World/JavaIntHash.h"
#include "../Minecraft.World/ArrayWithLength.h"
#include "ParticleType.h"
class ServerChunkCache; class ServerChunkCache;
class MinecraftServer; class MinecraftServer;
class Node; class Node;
class EntityTracker; class EntityTracker;
class PlayerChunkMap; class PlayerChunkMap;
class ArrayWithLength;
using namespace std; using namespace std;
class ServerLevel : public Level class ServerLevel : public Level
@ -180,5 +183,6 @@ public:
static C4JThread* m_updateThread; static C4JThread* m_updateThread;
static int runUpdate(void* lpParam); static int runUpdate(void* lpParam);
virtual void sendParticles(const ParticleType* type, bool longDistance, double x, double y, double z, int count, double dx, double dy, double dz, double speed, arrayWithLength<int> data);
virtual void sendParticles(const ParticleType* type, double x, double y, double z, int count, double dx, double dy, double dz, double speed, arrayWithLength<int> data);
}; };

View file

@ -2065,3 +2065,11 @@ void ServerPlayer::debug_setPosition(double x, double y, double z, double nYRot,
connection->teleport(x, y, z, nYRot, nXRot); connection->teleport(x, y, z, nYRot, nXRot);
} }
#endif #endif
bool ServerPlayer::isSpectator()
{
if (gameMode == nullptr)
{
return false;
}
return gameMode->getGameType() == GameType::SPECTATOR;
}

View file

@ -158,6 +158,7 @@ public:
static int getFlagIndexForChunk(const ChunkPos& pos, int dimension); // 4J - added static int getFlagIndexForChunk(const ChunkPos& pos, int dimension); // 4J - added
int getPlayerViewDistanceModifier(); // 4J Added, returns a number which is subtracted from the default view distance int getPlayerViewDistanceModifier(); // 4J Added, returns a number which is subtracted from the default view distance
bool isSpectator();
public: public:
// 4J Stu - Added hooks for the game rules // 4J Stu - Added hooks for the game rules

View file

@ -454,3 +454,8 @@ void ServerPlayerGameMode::setGameRules(GameRulesInstance *rules)
if(m_gameRules != nullptr) delete m_gameRules; if(m_gameRules != nullptr) delete m_gameRules;
m_gameRules = rules; m_gameRules = rules;
} }
GameType* ServerPlayerGameMode::getGameType()
{
return gameModeForPlayer;
}

View file

@ -32,6 +32,7 @@ private:
public: public:
void setGameRules(GameRulesInstance *rules); void setGameRules(GameRulesInstance *rules);
GameRulesInstance *getGameRules() { return m_gameRules; } GameRulesInstance *getGameRules() { return m_gameRules; }
GameType* getGameType();
public: public:
ServerPlayerGameMode(Level *level); ServerPlayerGameMode(Level *level);

View file

@ -181,7 +181,7 @@ const wchar_t *Textures::preLoaded[TN_COUNT] =
L"item/trapped", L"item/trapped",
L"item/trapped_double", L"item/trapped_double",
L"item/armor_stand", L"mob/armor_stand",
//L"item/christmas", //L"item/christmas",

View file

@ -647,6 +647,17 @@ set(_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_MODEL_GEOM
"${CMAKE_CURRENT_SOURCE_DIR}/ModelPart.h" "${CMAKE_CURRENT_SOURCE_DIR}/ModelPart.h"
"${CMAKE_CURRENT_SOURCE_DIR}/TexOffs.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TexOffs.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/TexOffs.h" "${CMAKE_CURRENT_SOURCE_DIR}/TexOffs.h"
"${CMAKE_CURRENT_SOURCE_DIR}/AbstractArmorLayer.h"
"${CMAKE_CURRENT_SOURCE_DIR}/AbstractArmorLayer.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/HumanoidArmorLayer.h"
"${CMAKE_CURRENT_SOURCE_DIR}/HumanoidArmorLayer.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ArmorStandArmorModel.h"
"${CMAKE_CURRENT_SOURCE_DIR}/ArmorStandArmorModel.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ItemInHandLayer.h"
"${CMAKE_CURRENT_SOURCE_DIR}/ItemInHandLayer.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/CustomHeadLayer.h"
"${CMAKE_CURRENT_SOURCE_DIR}/CustomHeadLayer.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/RenderLayer.h"
) )
source_group("net/minecraft/client/model/geom" FILES ${_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_MODEL_GEOM}) source_group("net/minecraft/client/model/geom" FILES ${_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_MODEL_GEOM})
@ -729,6 +740,8 @@ set(_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_PARTICLE
"${CMAKE_CURRENT_SOURCE_DIR}/TerrainParticle.h" "${CMAKE_CURRENT_SOURCE_DIR}/TerrainParticle.h"
"${CMAKE_CURRENT_SOURCE_DIR}/WaterDropParticle.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/WaterDropParticle.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/WaterDropParticle.h" "${CMAKE_CURRENT_SOURCE_DIR}/WaterDropParticle.h"
"${CMAKE_CURRENT_SOURCE_DIR}/ParticleType.h"
"${CMAKE_CURRENT_SOURCE_DIR}/ParticleType.cpp"
) )
source_group("net/minecraft/client/particle" FILES ${_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_PARTICLE}) source_group("net/minecraft/client/particle" FILES ${_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_PARTICLE})

View file

@ -1,4 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "com.mojang.nbt.h" #include "com.mojang.nbt.h"
#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.attributes.h"
#include "net.minecraft.world.entity.ai.navigation.h" #include "net.minecraft.world.entity.ai.navigation.h"
@ -11,33 +11,51 @@
#include "SynchedEntityData.h" #include "SynchedEntityData.h"
#include "SharedMonsterAttributes.h" #include "SharedMonsterAttributes.h"
#include "ArmorStand.h" #include "ArmorStand.h"
#include "..\Minecraft.Client\Textures.h" #include "BlockPos.h"
#include "MobCategory.h" #include "..\Minecraft.Client\ServerLevel.h"
#include "ParticleTypes.h" #include "ParticleTypes.h"
#include "Random.h"
#include "AABB.h"
const Rotations ArmorStand::DEFAULT_HEAD_POSE ( 0, 0, 0); const Rotations ArmorStand::DEFAULT_HEAD_POSE (0.0f, 0.0f, 0.0f);
const Rotations ArmorStand::DEFAULT_BODY_POSE ( 0, 0, 0); const Rotations ArmorStand::DEFAULT_BODY_POSE (0.0f, 0.0f, 0.0f);
const Rotations ArmorStand::DEFAULT_LEFT_ARM_POSE (-10, 0,-10); const Rotations ArmorStand::DEFAULT_LEFT_ARM_POSE (-10.0f, 0.0f, -10.0f);
const Rotations ArmorStand::DEFAULT_RIGHT_ARM_POSE (-15, 0, 10); const Rotations ArmorStand::DEFAULT_RIGHT_ARM_POSE (-15.0f, 0.0f, 10.0f);
const Rotations ArmorStand::DEFAULT_LEFT_LEG_POSE ( -1, 0, -1); const Rotations ArmorStand::DEFAULT_LEFT_LEG_POSE (-1.0f, 0.0f, -1.0f);
const Rotations ArmorStand::DEFAULT_RIGHT_LEG_POSE ( 1, 0, 1); const Rotations ArmorStand::DEFAULT_RIGHT_LEG_POSE (1.0f, 0.0f, 1.0f);
ArmorStand::ArmorStand(Level* level) ArmorStand::ArmorStand(Level* level)
: Mob(level) : LivingEntity(level)
{ {
ArmorStand::init();
}
void ArmorStand::init()
{
registerAttributes();
defineSynchedData();
lastHit = 0; lastHit = 0;
disabledSlots = 0; disabledSlots = 0;
invisible = false; invisible = false;
isMarkerFlag = false;
for (int i = 0; i < 5; i++) { for (int i = 0; i < equipmentCount; i++)
equipment[i] = nullptr; equipment[i] = nullptr;
headPose = DEFAULT_HEAD_POSE;
bodyPose = DEFAULT_BODY_POSE;
leftArmPose = DEFAULT_LEFT_ARM_POSE;
rightArmPose = DEFAULT_RIGHT_ARM_POSE;
leftLegPose = DEFAULT_LEFT_LEG_POSE;
rightLegPose = DEFAULT_RIGHT_LEG_POSE;
byte flags = entityData->getByte(DATA_CLIENT_FLAGS);
noPhysics = (flags & FLAG_NO_GRAVITY) != 0;
setSize(0.5f, 1.975f);
} }
this->defineSynchedData();
registerAttributes();
setHealth(getMaxHealth());
this->setSize(0.5f, 1.975f);
}
void ArmorStand::registerAttributes() void ArmorStand::registerAttributes()
{ {
@ -50,39 +68,130 @@ 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(2, wstring(L"")); // DATA_CUSTOM_NAME
entityData->define(DATA_CLIENT_FLAGS, static_cast<byte>(0)); entityData->define(DATA_CLIENT_FLAGS, static_cast<byte>(0));
entityData->define(DATA_HEAD_POSE, DEFAULT_HEAD_POSE);
entityData->define(DATA_HEAD_POSE_X, DEFAULT_HEAD_POSE.x); entityData->define(DATA_BODY_POSE, DEFAULT_BODY_POSE);
entityData->define(DATA_HEAD_POSE_Y, DEFAULT_HEAD_POSE.y); entityData->define(DATA_LEFT_ARM_POSE, DEFAULT_LEFT_ARM_POSE);
entityData->define(DATA_HEAD_POSE_Z, DEFAULT_HEAD_POSE.z); entityData->define(DATA_RIGHT_ARM_POSE, DEFAULT_RIGHT_ARM_POSE);
entityData->define(DATA_LEFT_LEG_POSE, DEFAULT_LEFT_LEG_POSE);
entityData->define(DATA_BODY_POSE_X, DEFAULT_BODY_POSE.x); entityData->define(DATA_RIGHT_LEG_POSE, DEFAULT_RIGHT_LEG_POSE);
entityData->define(DATA_BODY_POSE_Y, DEFAULT_BODY_POSE.y);
entityData->define(DATA_BODY_POSE_Z, DEFAULT_BODY_POSE.z);
entityData->define(DATA_LEFT_ARM_X, DEFAULT_LEFT_ARM_POSE.x);
entityData->define(DATA_LEFT_ARM_Y, DEFAULT_LEFT_ARM_POSE.y);
entityData->define(DATA_LEFT_ARM_Z, DEFAULT_LEFT_ARM_POSE.z);
entityData->define(DATA_RIGHT_ARM_X, DEFAULT_RIGHT_ARM_POSE.x);
entityData->define(DATA_RIGHT_ARM_Y, DEFAULT_RIGHT_ARM_POSE.y);
entityData->define(DATA_RIGHT_ARM_Z, DEFAULT_RIGHT_ARM_POSE.z);
entityData->define(DATA_LEFT_LEG_X, DEFAULT_LEFT_LEG_POSE.x);
entityData->define(DATA_LEFT_LEG_Y, DEFAULT_LEFT_LEG_POSE.y);
entityData->define(DATA_LEFT_LEG_Z, DEFAULT_LEFT_LEG_POSE.z);
entityData->define(DATA_RIGHT_LEG_X, DEFAULT_RIGHT_LEG_POSE.x);
entityData->define(DATA_RIGHT_LEG_Y, DEFAULT_RIGHT_LEG_POSE.y);
entityData->define(DATA_RIGHT_LEG_Z, DEFAULT_RIGHT_LEG_POSE.z);
} }
ArmorStand::~ArmorStand() {}
bool ArmorStand::isBaby() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_SMALL) != 0; }
bool ArmorStand::isSmall() const { return isBaby(); }
bool ArmorStand::isShowArms() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_SHOW_ARMS) != 0; }
bool ArmorStand::isNoBasePlate() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_NO_BASEPLATE)!= 0; }
bool ArmorStand::showBasePlate() const { return !isNoBasePlate(); }
bool ArmorStand::isMarker() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_MARKER) != 0; }
bool ArmorStand::isEffectiveAi() const
{
if (!LivingEntity::isEffectiveAi()) return false;
return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_NO_GRAVITY) == 0;
}
void ArmorStand::setSmall(bool v)
{
byte b = entityData->getByte(DATA_CLIENT_FLAGS);
entityData->set(DATA_CLIENT_FLAGS, v ? (byte)(b | FLAG_SMALL) : (byte)(b & ~FLAG_SMALL));
}
void ArmorStand::setShowArms(bool v)
{
byte b = entityData->getByte(DATA_CLIENT_FLAGS);
entityData->set(DATA_CLIENT_FLAGS, v ? (byte)(b | FLAG_SHOW_ARMS) : (byte)(b & ~FLAG_SHOW_ARMS));
}
void ArmorStand::setNoBasePlate(bool v)
{
byte b = entityData->getByte(DATA_CLIENT_FLAGS);
entityData->set(DATA_CLIENT_FLAGS, v ? (byte)(b | FLAG_NO_BASEPLATE) : (byte)(b & ~FLAG_NO_BASEPLATE));
}
void ArmorStand::setMarker(bool v)
{
byte b = entityData->getByte(DATA_CLIENT_FLAGS);
entityData->set(DATA_CLIENT_FLAGS, v ? (byte)(b | FLAG_MARKER) : (byte)(b & ~FLAG_MARKER));
}
void ArmorStand::setNoGravity(bool v)
{
byte b = entityData->getByte(DATA_CLIENT_FLAGS);
entityData->set(DATA_CLIENT_FLAGS, v ? (byte)(b | FLAG_NO_GRAVITY) : (byte)(b & ~FLAG_NO_GRAVITY));
}
void ArmorStand::setInvisible(bool v)
{
invisible = v;
Entity::setInvisible(v);
}
Rotations ArmorStand::getHeadPose() const { return entityData->getRotations(DATA_HEAD_POSE); }
Rotations ArmorStand::getBodyPose() const { return entityData->getRotations(DATA_BODY_POSE); }
Rotations ArmorStand::getLeftArmPose() const { return entityData->getRotations(DATA_LEFT_ARM_POSE); }
Rotations ArmorStand::getRightArmPose() const { return entityData->getRotations(DATA_RIGHT_ARM_POSE); }
Rotations ArmorStand::getLeftLegPose() const { return entityData->getRotations(DATA_LEFT_LEG_POSE); }
Rotations ArmorStand::getRightLegPose() const { return entityData->getRotations(DATA_RIGHT_LEG_POSE); }
void ArmorStand::setHeadPose (const Rotations& r) { headPose = r; entityData->set(DATA_HEAD_POSE, r); }
void ArmorStand::setBodyPose (const Rotations& r) { bodyPose = r; entityData->set(DATA_BODY_POSE, r); }
void ArmorStand::setLeftArmPose (const Rotations& r) { leftArmPose = r; entityData->set(DATA_LEFT_ARM_POSE, r); }
void ArmorStand::setRightArmPose(const Rotations& r) { rightArmPose = r; entityData->set(DATA_RIGHT_ARM_POSE, r); }
void ArmorStand::setLeftLegPose (const Rotations& r) { leftLegPose = r; entityData->set(DATA_LEFT_LEG_POSE, r); }
void ArmorStand::setRightLegPose(const Rotations& r) { rightLegPose = r; entityData->set(DATA_RIGHT_LEG_POSE, r); }
float ArmorStand::getEyeHeight()
{
return isSmall() ? (bbHeight * 0.5f) : (bbHeight * 0.9f);
}
bool ArmorStand::isPickable()
{
if (!LivingEntity::isPickable()) return false;
return !isMarker();
}
bool ArmorStand::isPushable() { return false; }
bool ArmorStand::ignoreExplosion()
{
return isInvisible();
}
void ArmorStand::kill()
{
remove();
}
bool ArmorStand::shouldRenderAtSqrDistance(double distSq)
{
double size = getBoundingBox()->getSize();
if (size == 0.0) size = 4.0;
double limit = size * 64.0;
return distSq < limit * limit;
}
void ArmorStand::updateBoundingBox(bool markerMode)
{
float ox = x, oy = y, oz = z;
if (markerMode) setSize(0.0f, 0.0f);
else setSize(0.5f, 1.975f);
moveTo(ox, oy, oz, yRot, xRot);
}
void ArmorStand::updateInvisibilityStatus()
{
setInvisible(invisible);
}
void ArmorStand::tick() void ArmorStand::tick()
{ {
float lockedRot = this->yRot; float lockedRot = this->yRot;
if (this->isInWater()|| this->isInLava()) {
this->yd -= 0.0392;
}
LivingEntity::tick(); LivingEntity::tick();
this->yRot = lockedRot; this->yRot = lockedRot;
this->yRotO = lockedRot; this->yRotO = lockedRot;
@ -91,328 +200,452 @@ void ArmorStand::tick()
this->yHeadRot = lockedRot; this->yHeadRot = lockedRot;
this->yHeadRotO = lockedRot; this->yHeadRotO = lockedRot;
auto syncPose = [&](int slot, Rotations& local)
{
Rotations net = entityData->getRotations(slot);
if (local != net) { local = net; entityData->set(slot, net); }
};
syncPose(DATA_HEAD_POSE, headPose);
syncPose(DATA_BODY_POSE, bodyPose);
syncPose(DATA_LEFT_ARM_POSE, leftArmPose);
syncPose(DATA_RIGHT_ARM_POSE, rightArmPose);
syncPose(DATA_LEFT_LEG_POSE, leftLegPose);
syncPose(DATA_RIGHT_LEG_POSE, rightLegPose);
bool markerNow = (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_MARKER) != 0;
if (isMarkerFlag && !markerNow)
{
float ox = x, oy = y, oz = z;
setSize(0.5f, 1.975f);
moveTo(ox, oy, oz, yRot, xRot);
isMarkerFlag = false;
}
else if (!isMarkerFlag && markerNow)
{
float ox = x, oy = y, oz = z;
setSize(0.0f, 0.0f);
moveTo(ox, oy, oz, yRot, xRot);
isMarkerFlag = true;
}
}
void ArmorStand::brokenByAnything()
{
for (int i = 0; i < equipmentCount; i++)
{
if (equipment[i] && equipment[i]->count > 0)
{
spawnAtLocation(equipment[i], 0.0f);
equipment[i] = nullptr;
}
}
}
void ArmorStand::brokenByPlayer(shared_ptr<Player> player, DamageSource* source)
{
spawnAtLocation(Item::armor_stand_Id, 1);
brokenByAnything();
}
void ArmorStand::causeDamage(float damage)
{
float h = getHealth();
h -= damage;
if (h <= 0.5f)
{
brokenByAnything();
remove();
}
else
{
setHealth(h);
}
}
bool ArmorStand::hurt(DamageSource* source, float damage)
{
if (isInvulnerable() || level->isClientSide || removed || isMarker()) return false;
if (source != nullptr && source->getMsgId() == eEntityDamageType_Suffocate) return false;
if (source->isExplosion())
{
brokenByAnything();
remove();
return true;
}
bool isFireDamage = source->isFire();
if (dynamic_cast<EntityDamageSource*>(source) != nullptr)
{
shared_ptr<Entity> attacker = source->getEntity();
if (attacker != nullptr && attacker->instanceof(eTYPE_PLAYER))
{
if (dynamic_pointer_cast<Player>(attacker)->abilities.instabuild)
{
level->broadcastEntityEvent(shared_from_this(), (byte)31);
remove();
return true;
}
}
}
if (isFireDamage)
{
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);
brokenByAnything();
remove();
return true;
}
}
void ArmorStand::pushEntities()
{
AABB* myBox = getBoundingBox();
AABB* grown = myBox->grow(0.2, 0.0, 0.2);
auto* entities = level->getEntities(shared_from_this(), grown);
if (!entities) return;
for (auto& e : *entities)
{
if (!e) continue;
if (!e->instanceof(eTYPE_MINECART)) continue;
if (distanceToSqr(e) > 0.2) continue;
e->push(shared_from_this());
}
}
shared_ptr<ItemInstance> ArmorStand::getCarriedItem() { return equipment[SLOT_WEAPON]; }
shared_ptr<ItemInstance> ArmorStand::getCarried(int slot) { return (slot >= 0 && slot < equipmentCount) ? equipment[slot] : nullptr; }
shared_ptr<ItemInstance> ArmorStand::getArmor(int pos)
{
int idx = pos + 1;
return (idx >= 1 && idx < equipmentCount) ? equipment[idx] : nullptr;
}
void ArmorStand::setEquippedSlot(int slot, shared_ptr<ItemInstance> item)
{
if (slot >= 0 && slot < equipmentCount) equipment[slot] = item;
}
ItemInstanceArray ArmorStand::getEquipmentSlots() { return ItemInstanceArray(equipment, equipmentCount); }
int ArmorStand::getEquipmentSlotForItem(shared_ptr<ItemInstance> item) const
{
if (!item) return SLOT_WEAPON;
return Mob::getEquipmentSlotForItem(item);
}
bool ArmorStand::setSlot(int inventorySlot, shared_ptr<ItemInstance> item)
{
int localSlot;
if (inventorySlot == 0x63) localSlot = SLOT_WEAPON;
else
{
localSlot = inventorySlot - 0x63;
if (localSlot < 0 || localSlot >= equipmentCount) return false;
}
if (item)
{
int naturalSlot = getEquipmentSlotForItem(item);
if (naturalSlot != localSlot)
{
if (localSlot == SLOT_HELM)
{
auto bi = dynamic_cast<TileItem*>(item->getItem());
if (!bi) return false;
}
else return false;
}
}
setEquippedSlot(localSlot, item);
return true;
}
void ArmorStand::swapItem(shared_ptr<Player> player, int slot)
{
shared_ptr<ItemInstance> standItem = equipment[slot];
shared_ptr<ItemInstance> playerItem = player->getCarriedItem();
int disabledFlags = disabledSlots;
if (!standItem)
{
if ((disabledFlags & (1 << (slot + 0x10))) != 0) return;
if (!playerItem) goto do_take;
}
if ((disabledFlags & (1 << (slot + 8))) != 0) goto do_take;
if (playerItem)
{
if (player->abilities.instabuild)
{
auto toPlace = ItemInstance::clone(playerItem);
toPlace->count = 1;
setEquippedSlot(slot, toPlace);
}
else
{
auto toPlace = ItemInstance::clone(playerItem);
toPlace->count = 1;
setEquippedSlot(slot, toPlace);
if (standItem)
{
if (playerItem->count > 1) { playerItem->remove(1); if (!player->inventory->add(standItem)) spawnAtLocation(standItem, 0.0f); }
else player->inventory->setItem(player->inventory->selected, standItem);
}
else playerItem->remove(1);
}
return;
}
do_take:
if (standItem) { player->inventory->setItem(player->inventory->selected, standItem); setEquippedSlot(slot, nullptr); }
} }
bool ArmorStand::interact(shared_ptr<Player> player) bool ArmorStand::interact(shared_ptr<Player> player)
{ {
if (level->isClientSide) return true; if (level->isClientSide) return true;
if (isMarker()) return false; if (isMarker()) return false;
if (player->isSpectator()) return true;
float dX = this->x - player->x; float dX = this->x - player->x;
float dZ = this->z - player->z; float dZ = this->z - player->z;
float distHoriz = sqrt(dX * dX + dZ * dZ); float distHoriz = sqrtf(dX * dX + dZ * dZ);
float pitchRad = player->xRot * (3.14159265f / 180.0f); float pitchRad = player->xRot * (3.14159265f / 180.0f);
float lookYDiff = -tan(pitchRad) * distHoriz; float lookYDiff = -tanf(pitchRad) * distHoriz;
float hitY = (player->y + 1.62f + lookYDiff) - this->y; float hitY = (player->y + 1.62f + lookYDiff) - this->y;
if (isSmall()) hitY *= 2.0f;
int targetSlot = SLOT_WEAPON; shared_ptr<ItemInstance> carried = player->getCarriedItem();
if (hitY >= 0.1f && hitY < 0.55f) {
int targetSlot;
if (carried)
{
targetSlot = getEquipmentSlotForItem(carried);
}
else
{
if (hitY >= 0.1f && hitY < 0.55f) targetSlot = SLOT_BOOTS;
else if (hitY >= 0.55f && hitY < 0.9f) targetSlot = SLOT_LEGGINGS;
else if (hitY >= 0.9f && hitY < 1.6f) targetSlot = SLOT_CHEST;
else if (hitY >= 1.6f) targetSlot = SLOT_HELM;
else targetSlot = SLOT_WEAPON;
}
if (targetSlot == SLOT_WEAPON && !isShowArms()) return false;
if ((disabledSlots & (1 << targetSlot)) != 0) return false;
shared_ptr<ItemInstance> standItem = equipment[targetSlot];
if (carried)
{
auto toPlace = ItemInstance::clone(carried);
toPlace->count = 1;
setEquippedSlot(targetSlot, toPlace);
if (standItem)
{
if (carried->count > 1)
{
carried->remove(1);
if (!player->inventory->add(standItem))
spawnAtLocation(standItem, 0.0f);
}
else
{
player->inventory->setItem(player->inventory->selected, standItem);
}
}
else
{
carried->remove(1);
}
}
else if (standItem)
{
player->inventory->setItem(player->inventory->selected, standItem);
setEquippedSlot(targetSlot, nullptr);
}
return true;
}
bool ArmorStand::interactAt(shared_ptr<Player> player, const Vec3& hitVec)
{
if (isMarker()) return false;
if (level->isClientSide) return true;
if (player->isSpectator()) return true;
shared_ptr<ItemInstance> carried = player->getCarriedItem();
int targetSlot;
if (carried)
{
targetSlot = getEquipmentSlotForItem(carried);
}
else
{
float hitY = (float)hitVec.y;
bool isSmallStand = isSmall();
if (isSmallStand) hitY *= 2.0f;
float bootsMax = isSmallStand ? 0.9f : 0.55f;
float legsMin = isSmallStand ? 1.2f : 0.9f;
float legsMax = isSmallStand ? 1.9f : 1.6f;
targetSlot = SLOT_WEAPON;
if (hitY >= 0.1f && hitY < bootsMax)
targetSlot = SLOT_BOOTS; targetSlot = SLOT_BOOTS;
} else if (hitY >= 0.55f && hitY < 0.9f) { else if (hitY >= legsMin && hitY < legsMax)
targetSlot = SLOT_LEGGINGS; targetSlot = SLOT_LEGGINGS;
} else if (hitY >= 0.9f && hitY < 1.6f) { if (hitY >= 1.6f && equipment[SLOT_HELM])
targetSlot = SLOT_CHEST;
} else if (hitY >= 1.6f) {
targetSlot = SLOT_HELM; targetSlot = SLOT_HELM;
} }
shared_ptr<ItemInstance> playerItem = player->getCarriedItem();
if (targetSlot == SLOT_WEAPON && !isShowArms()) return false;
int slotToInteract = (playerItem != nullptr) ? getEquipmentSlotForItem(playerItem) : targetSlot; if ((disabledSlots & (1 << targetSlot)) != 0) return false;
if (isSlotDisabled(slotToInteract)) return false; swapItem(player, targetSlot);
shared_ptr<ItemInstance> standItem = getItemInSlot(slotToInteract);
if (playerItem != nullptr) {
shared_ptr<ItemInstance> toPlace = ItemInstance::clone(playerItem);
toPlace->count = 1;
setEquippedSlot(slotToInteract, toPlace);
if (standItem != nullptr) {
if (playerItem->count > 1) {
playerItem->remove(1);
if (!player->inventory->add(standItem)) spawnAtLocation(standItem, 0.0f);
} else {
player->inventory->setItem(player->inventory->selected, standItem);
}
} else {
playerItem->remove(1);
}
}
else if (standItem != nullptr) {
player->inventory->setItem(player->inventory->selected, standItem);
setEquippedSlot(slotToInteract, nullptr);
}
return true;
}
bool ArmorStand::hurt(DamageSource *source, float damage)
{
if (isInvulnerable() || level->isClientSide || removed || isMarker()) return false;
if (source != nullptr && source->getMsgId() == eEntityDamageType_Suffocate) return false;
bool isFireDamage = source->isFire();
if (dynamic_cast<EntityDamageSource *>(source) != nullptr) {
shared_ptr<Entity> attacker = source->getEntity();
if (attacker != nullptr && attacker->instanceof(eTYPE_PLAYER)) {
if (dynamic_pointer_cast<Player>(attacker)->abilities.instabuild) {
level->broadcastEntityEvent(shared_from_this(), (byte)31);
remove();
return true;
}
}
}
long long now = (long long)tickCount;
if (isFireDamage) {
float currentHealth = this->getHealth() - 0.1f;
this->setHealth(currentHealth);
if (currentHealth <= 0) {
//level->broadcastEntityEvent(shared_from_this(), (byte)31);
remove();
return true; return true;
} }
int ArmorStand::test_interactAt(shared_ptr<Player> player, const Vec3& hitVec)
return false;
}
if (now - lastHit > 5) {
level->broadcastEntityEvent(shared_from_this(), (byte)32);
lastHit = now;
return true;
} else {
level->broadcastEntityEvent(shared_from_this(), (byte)31);
remove();
spawnAtLocation(Item::armor_stand_Id, 1);
for (int i = 0; i < 5; i++) {
if (equipment[i] != nullptr) spawnAtLocation(equipment[i], 0.0f);
}
return true;
}
}
bool ArmorStand::isPickable()
{ {
return !removed && !isMarker(); if (isMarker()) return 0;
if (player->isSpectator()) return 0;
shared_ptr<ItemInstance> carried = player->getCarriedItem();
int playerSlot = carried ? getEquipmentSlotForItem(carried) : SLOT_WEAPON;
bool hasStandItem = equipment[playerSlot] != nullptr;
if ((disabledSlots & (1 << playerSlot)) != 0 && (disabledSlots & 1) != 0) return 0;
if (!carried) return hasStandItem ? 2 : 0;
return hasStandItem ? 3 : 1;
} }
byte ArmorStand::setBit(byte oldBit, int offset, bool value) void ArmorStand::readPose(CompoundTag* poseTag)
{ {
if (value) oldBit = (byte)(oldBit | offset); auto loadRot = [&](const wchar_t* key, const Rotations& def, int dataSlot)
else oldBit = (byte)(oldBit & ~offset);
return oldBit;
}
bool ArmorStand::isSmall() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_SMALL) != 0; }
bool ArmorStand::showArms() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_SHOW_ARMS) != 0; }
bool ArmorStand::showBasePlate() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_NO_BASEPLATE) == 0; }
bool ArmorStand::isMarker() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_MARKER) != 0; }
void ArmorStand::setSmall(bool v) { entityData->set(DATA_CLIENT_FLAGS, setBit(entityData->getByte(DATA_CLIENT_FLAGS), FLAG_SMALL, v)); }
void ArmorStand::setShowArms(bool v) { entityData->set(DATA_CLIENT_FLAGS, setBit(entityData->getByte(DATA_CLIENT_FLAGS), FLAG_SHOW_ARMS, v)); }
void ArmorStand::setNoBasePlate(bool v) { entityData->set(DATA_CLIENT_FLAGS, setBit(entityData->getByte(DATA_CLIENT_FLAGS), FLAG_NO_BASEPLATE, v)); }
void ArmorStand::setMarker(bool v) { entityData->set(DATA_CLIENT_FLAGS, setBit(entityData->getByte(DATA_CLIENT_FLAGS), FLAG_MARKER, v)); }
Rotations ArmorStand::readRotation(int slotX) const
{ {
return Rotations( Rotations r = def;
entityData->getFloat(slotX),
entityData->getFloat(slotX + 1), ListTag<FloatTag>* list = static_cast<ListTag<FloatTag>*>(
entityData->getFloat(slotX + 2) static_cast<void*>(poseTag->getList(key)));
); if (list && list->size() >= 3)
r = Rotations(list);
entityData->set(dataSlot, r);
};
loadRot(L"Head", DEFAULT_HEAD_POSE, DATA_HEAD_POSE);
loadRot(L"Body", DEFAULT_BODY_POSE, DATA_BODY_POSE);
loadRot(L"LeftArm", DEFAULT_LEFT_ARM_POSE, DATA_LEFT_ARM_POSE);
loadRot(L"RightArm", DEFAULT_RIGHT_ARM_POSE, DATA_RIGHT_ARM_POSE);
loadRot(L"LeftLeg", DEFAULT_LEFT_LEG_POSE, DATA_LEFT_LEG_POSE);
loadRot(L"RightLeg", DEFAULT_RIGHT_LEG_POSE, DATA_RIGHT_LEG_POSE);
headPose = entityData->getRotations(DATA_HEAD_POSE);
bodyPose = entityData->getRotations(DATA_BODY_POSE);
leftArmPose = entityData->getRotations(DATA_LEFT_ARM_POSE);
rightArmPose = entityData->getRotations(DATA_RIGHT_ARM_POSE);
leftLegPose = entityData->getRotations(DATA_LEFT_LEG_POSE);
rightLegPose = entityData->getRotations(DATA_RIGHT_LEG_POSE);
} }
void ArmorStand::writeRotation(int slotX, const Rotations &r) CompoundTag* ArmorStand::writePose()
{ {
entityData->set(slotX, r.x); CompoundTag* pose = new CompoundTag();
entityData->set(slotX + 1, r.y); auto save = [&](const wchar_t* key, const Rotations& cur, const Rotations& def)
entityData->set(slotX + 2, r.z); { if (cur != def) pose->put(key, cur.save()); };
save(L"Head", headPose, DEFAULT_HEAD_POSE);
save(L"Body", bodyPose, DEFAULT_BODY_POSE);
save(L"LeftArm", leftArmPose, DEFAULT_LEFT_ARM_POSE);
save(L"RightArm", rightArmPose, DEFAULT_RIGHT_ARM_POSE);
save(L"LeftLeg", leftLegPose, DEFAULT_LEFT_LEG_POSE);
save(L"RightLeg", rightLegPose, DEFAULT_RIGHT_LEG_POSE);
return pose;
} }
Rotations ArmorStand::getHeadPose() const { return readRotation(DATA_HEAD_POSE_X); }
Rotations ArmorStand::getBodyPose() const { return readRotation(DATA_BODY_POSE_X); }
Rotations ArmorStand::getLeftArmPose() const { return readRotation(DATA_LEFT_ARM_X); }
Rotations ArmorStand::getRightArmPose() const { return readRotation(DATA_RIGHT_ARM_X); }
Rotations ArmorStand::getLeftLegPose() const { return readRotation(DATA_LEFT_LEG_X); }
Rotations ArmorStand::getRightLegPose() const { return readRotation(DATA_RIGHT_LEG_X); }
void ArmorStand::setHeadPose (const Rotations &r) { writeRotation(DATA_HEAD_POSE_X, r); }
void ArmorStand::setBodyPose (const Rotations &r) { writeRotation(DATA_BODY_POSE_X, r); }
void ArmorStand::setLeftArmPose (const Rotations &r) { writeRotation(DATA_LEFT_ARM_X, r); }
void ArmorStand::setRightArmPose(const Rotations &r) { writeRotation(DATA_RIGHT_ARM_X, r); }
void ArmorStand::setLeftLegPose (const Rotations &r) { writeRotation(DATA_LEFT_LEG_X, r); }
void ArmorStand::setRightLegPose(const Rotations &r) { writeRotation(DATA_RIGHT_LEG_X, r); }
void ArmorStand::readAdditionalSaveData(CompoundTag* tag) void ArmorStand::readAdditionalSaveData(CompoundTag* tag)
{ {
LivingEntity::readAdditionalSaveData(tag); LivingEntity::readAdditionalSaveData(tag);
invisible = tag->getBoolean(L"Invisible"); if (tag->contains(L"ArmorStandEquipment", 9))
disabledSlots = tag->getInt(L"DisabledSlots"); {
setInvisible(invisible); ListTag<CompoundTag>* eqList = static_cast<ListTag<CompoundTag>*>(
static_cast<void*>(tag->getList(L"ArmorStandEquipment")));
if (eqList)
for (int i = 0; i < equipmentCount && i < eqList->size(); i++)
equipment[i] = ItemInstance::fromTag(eqList->get(i));
}
setInvisible (tag->getBoolean(L"Invisible"));
setSmall (tag->getBoolean(L"Small")); setSmall (tag->getBoolean(L"Small"));
setShowArms (tag->getBoolean(L"ShowArms")); setShowArms (tag->getBoolean(L"ShowArms"));
setNoBasePlate (tag->getBoolean(L"NoBasePlate")); setNoBasePlate (tag->getBoolean(L"NoBasePlate"));
setNoGravity (tag->getBoolean(L"NoGravity"));
setMarker (tag->getBoolean(L"Marker")); setMarker (tag->getBoolean(L"Marker"));
disabledSlots = tag->getInt(L"DisabledSlots");
isMarkerFlag = isMarker();
noPhysics = (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_NO_GRAVITY) != 0;
if (tag->contains(L"Pose"))
{
CompoundTag* pose = tag->getCompound(L"Pose"); CompoundTag* pose = tag->getCompound(L"Pose");
auto loadRot = [&](const wchar_t *key, const Rotations &def) -> Rotations { if (pose && !pose->isEmpty()) readPose(pose);
if (!pose->contains(key)) return def;
ListTag<FloatTag> *list = (ListTag<FloatTag> *)pose->getList(key);
if (!list || list->size() < 3) return def;
return Rotations(list->get(0)->data, list->get(1)->data, list->get(2)->data);
};
setHeadPose (loadRot(L"Head", DEFAULT_HEAD_POSE));
setBodyPose (loadRot(L"Body", DEFAULT_BODY_POSE));
setLeftArmPose (loadRot(L"LeftArm", DEFAULT_LEFT_ARM_POSE));
setRightArmPose(loadRot(L"RightArm", DEFAULT_RIGHT_ARM_POSE));
setLeftLegPose (loadRot(L"LeftLeg", DEFAULT_LEFT_LEG_POSE));
setRightLegPose(loadRot(L"RightLeg", DEFAULT_RIGHT_LEG_POSE));
}
if (tag->contains(L"ArmorStandEquipment"))
{
ListTag<CompoundTag> *eqList = (ListTag<CompoundTag> *)tag->getList(L"ArmorStandEquipment");
if (eqList) {
for (int i = 0; i < 5 && i < eqList->size(); i++) {
CompoundTag *itemTag = eqList->get(i);
if (itemTag->contains(L"id")) {
equipment[i] = ItemInstance::fromTag(itemTag);
} else {
equipment[i] = nullptr;
}
}
}
}
} }
void ArmorStand::addAdditonalSaveData(CompoundTag* tag) void ArmorStand::addAdditonalSaveData(CompoundTag* tag)
{ {
LivingEntity::addAdditonalSaveData(tag); LivingEntity::addAdditonalSaveData(tag);
tag->putBoolean(L"Invisible", isInvisible());
tag->putBoolean(L"Small", isSmall());
tag->putBoolean(L"ShowArms", showArms());
tag->putBoolean(L"NoBasePlate", !showBasePlate());
tag->putInt (L"DisabledSlots", disabledSlots);
if (isMarker()) tag->putBoolean(L"Marker", true);
auto saveRot = [](const Rotations &r) -> ListTag<FloatTag> * {
ListTag<FloatTag> *list = new ListTag<FloatTag>();
list->add(new FloatTag(L"", r.x));
list->add(new FloatTag(L"", r.y));
list->add(new FloatTag(L"", r.z));
return list;
};
CompoundTag *pose = new CompoundTag();
pose->put(L"Head", saveRot(getHeadPose()));
pose->put(L"Body", saveRot(getBodyPose()));
pose->put(L"LeftArm", saveRot(getLeftArmPose()));
pose->put(L"RightArm", saveRot(getRightArmPose()));
pose->put(L"LeftLeg", saveRot(getLeftLegPose()));
pose->put(L"RightLeg", saveRot(getRightLegPose()));
tag->put(L"Pose", pose);
ListTag<CompoundTag>* eqList = new ListTag<CompoundTag>(); ListTag<CompoundTag>* eqList = new ListTag<CompoundTag>();
for (int i = 0; i < 5; i++) { for (int i = 0; i < equipmentCount; i++)
{
CompoundTag* itemTag = new CompoundTag(); CompoundTag* itemTag = new CompoundTag();
if (equipment[i] != nullptr) { if (equipment[i]) equipment[i]->save(itemTag);
equipment[i]->save(itemTag);
}
eqList->add(itemTag); eqList->add(itemTag);
} }
tag->put(L"ArmorStandEquipment", eqList); tag->put(L"ArmorStandEquipment", eqList);
}
shared_ptr<ItemInstance> ArmorStand::getCarriedItem() if (isInvisible()) tag->putBoolean(L"Invisible", true);
{ tag->putBoolean(L"Small", isSmall());
return equipment[SLOT_WEAPON]; tag->putBoolean(L"ShowArms", isShowArms());
} tag->putBoolean(L"NoBasePlate", isNoBasePlate());
tag->putInt (L"DisabledSlots",disabledSlots);
shared_ptr<ItemInstance> ArmorStand::getCarried(int slot) if (isMarker()) tag->putBoolean(L"Marker", true);
{ tag->putBoolean(L"NoGravity", noPhysics);
if (slot == SLOT_WEAPON) return getCarriedItem(); tag->put(L"Pose", writePose());
else if (slot >= SLOT_BOOTS && slot <= SLOT_HELM) return getArmor(slot - 1);
return nullptr;
}
shared_ptr<ItemInstance> ArmorStand::getArmor(int pos)
{
if (pos >= 0 && pos < 4) {
return equipment[pos + 1];
}
return nullptr;
}
void ArmorStand::setEquippedSlot(int slot, shared_ptr<ItemInstance> item)
{
if (slot >= 0 && slot < 5) {
equipment[slot] = item;
}
}
ItemInstanceArray ArmorStand::getEquipmentSlots()
{
return equipment;
}
int ArmorStand::getEquipmentSlotForItem(shared_ptr<ItemInstance> item) const
{
if (!item) return SLOT_WEAPON;
int id = item->id;
const int HELMET_IDS[] = {298, 302, 306, 310, 314};
const int CHEST_IDS[] = {299, 303, 307, 311, 315};
const int LEGS_IDS[] = {300, 304, 308, 312, 316};
const int BOOTS_IDS[] = {301, 305, 309, 313, 317};
const int HEAD_IDS[] = {397, 144, 145, 146, 86};
for (int helm : HELMET_IDS) if (id == helm) return SLOT_HELM;
for (int chest : CHEST_IDS) if (id == chest) return SLOT_CHEST;
for (int legs : LEGS_IDS) if (id == legs) return SLOT_LEGGINGS;
for (int boots : BOOTS_IDS) if (id == boots) return SLOT_BOOTS;
for (int head : HEAD_IDS) if (id == head) return SLOT_HELM;
return SLOT_WEAPON;
}
bool ArmorStand::isSlotDisabled(int slot) const
{
if (slot == SLOT_WEAPON && !showArms()) return true;
return false;
}
shared_ptr<ItemInstance> ArmorStand::getItemInSlot(int slot)
{
if (slot == SLOT_WEAPON) {
return getCarriedItem();
} else if (slot >= SLOT_BOOTS && slot <= SLOT_HELM) {
return getArmor(slot - 1);
}
return nullptr;
} }
@ -420,39 +653,19 @@ void ArmorStand::handleEntityEvent(byte id)
{ {
if (id == 31) if (id == 31)
{ {
int woodId = (Tile::wood != nullptr) ? Tile::wood->id : 5; int woodId = Tile::wood ? Tile::wood->id : 5;
ePARTICLE_TYPE woodParticle = PARTICLE_TILECRACK(woodId, 0); ePARTICLE_TYPE p = PARTICLE_TILECRACK(woodId, 0);
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
double xa = random->nextGaussian() * 0.01; double xa = random->nextGaussian() * 0.01;
double ya = -0.05; double ya = -0.05;
double za = random->nextGaussian() * 0.01; double za = random->nextGaussian() * 0.01;
double px = x + (random->nextFloat() * 0.1f - 0.05f); double px = x + (random->nextFloat() * 0.1f - 0.05f);
double py = y + (bbHeight * 0.6f) + (random->nextFloat() * 0.2f); double py = y + (bbHeight * 0.6f) + (random->nextFloat() * 0.2f);
double pz = z + (random->nextFloat() * 0.1f - 0.05f); double pz = z + (random->nextFloat() * 0.1f - 0.05f);
level->addParticle(p, px, py, pz, xa, ya, za);
level->addParticle(woodParticle, px, py, pz, xa, ya, za);
} }
} }
else if (id == 32) else if (id == 32) lastHit = (long long)tickCount;
lastHit = (long long)tickCount; else LivingEntity::handleEntityEvent(id);
else
LivingEntity::handleEntityEvent(id);
} }
bool ArmorStand::updateInWaterState()
{
return Entity::updateInWaterState();
}

View file

@ -1,18 +1,14 @@
#pragma once #pragma once
#include "Mob.h" #include "Mob.h"
#include "Rotations.h"
#include "SynchedEntityData.h" #include "SynchedEntityData.h"
#include "Vec3.h"
#include "Random.h"
struct Rotations class ArmorStand : public LivingEntity
{
float x, y, z;
Rotations() : x(0), y(0), z(0) {}
Rotations(float x, float y, float z) : x(x), y(y), z(z) {}
};
class ArmorStand : public Mob
{ {
public: public:
eINSTANCEOF GetType() { return eTYPE_ARMORSTAND; } eINSTANCEOF GetType() override { return eTYPE_ARMORSTAND; }
static Entity* create(Level* level) { return new ArmorStand(level); } static Entity* create(Level* level) { return new ArmorStand(level); }
static const Rotations DEFAULT_HEAD_POSE; static const Rotations DEFAULT_HEAD_POSE;
@ -23,50 +19,63 @@ public:
static const Rotations DEFAULT_RIGHT_LEG_POSE; static const Rotations DEFAULT_RIGHT_LEG_POSE;
private: private:
static const int DATA_CLIENT_FLAGS = 10; static const int DATA_CLIENT_FLAGS = 0xA;
static const int DATA_HEAD_POSE_X = 11; static const int DATA_HEAD_POSE = 0xB;
static const int DATA_HEAD_POSE_Y = 12; static const int DATA_BODY_POSE = 0xC;
static const int DATA_HEAD_POSE_Z = 13; static const int DATA_LEFT_ARM_POSE = 0xD;
static const int DATA_BODY_POSE_X = 14; static const int DATA_RIGHT_ARM_POSE = 0xE;
static const int DATA_BODY_POSE_Y = 15; static const int DATA_LEFT_LEG_POSE = 0xF;
static const int DATA_BODY_POSE_Z = 16; static const int DATA_RIGHT_LEG_POSE = 0x10;
static const int DATA_LEFT_ARM_X = 17;
static const int DATA_LEFT_ARM_Y = 18;
static const int DATA_LEFT_ARM_Z = 19;
static const int DATA_RIGHT_ARM_X = 20;
static const int DATA_RIGHT_ARM_Y = 21;
static const int DATA_RIGHT_ARM_Z = 22;
static const int DATA_LEFT_LEG_X = 23;
static const int DATA_LEFT_LEG_Y = 24;
static const int DATA_LEFT_LEG_Z = 25;
static const int DATA_RIGHT_LEG_X = 26;
static const int DATA_RIGHT_LEG_Y = 27;
static const int DATA_RIGHT_LEG_Z = 28;
static const int FLAG_SMALL = 1; static const int FLAG_SMALL = 1;
static const int FLAG_NO_GRAVITY = 2;
static const int FLAG_SHOW_ARMS = 4; static const int FLAG_SHOW_ARMS = 4;
static const int FLAG_NO_BASEPLATE= 8; static const int FLAG_NO_BASEPLATE= 8;
static const int FLAG_MARKER = 16; static const int FLAG_MARKER = 16;
public: public:
long long lastHit; static const int SLOT_WEAPON = 0;
static const int SLOT_BOOTS = 1;
static const int SLOT_LEGGINGS = 2;
static const int SLOT_CHEST = 3;
static const int SLOT_HELM = 4;
static const int equipmentCount = 5;
private: private:
shared_ptr<ItemInstance> equipment[equipmentCount];
Rotations headPose;
Rotations bodyPose;
Rotations leftArmPose;
Rotations rightArmPose;
Rotations leftLegPose;
Rotations rightLegPose;
int disabledSlots; int disabledSlots;
bool invisible; bool invisible;
bool isMarkerFlag;
bool noPhysics;
public: public:
ArmorStand(Level *level); long long lastHit;
virtual ~ArmorStand() {}
explicit ArmorStand(Level* level);
virtual ~ArmorStand();
bool isBaby() const;
bool isSmall() const; bool isSmall() const;
bool showArms() const; bool isShowArms() const;
bool isNoBasePlate() const;
bool showBasePlate() const; bool showBasePlate() const;
bool isMarker() const; bool isMarker() const;
bool isEffectiveAi() const;
void setSmall (bool v); void setSmall (bool v);
void setShowArms (bool v); void setShowArms (bool v);
void setNoBasePlate (bool v); void setNoBasePlate (bool v);
void setMarker (bool v); void setMarker (bool v);
void setNoGravity (bool v);
void setInvisible (bool v);
Rotations getHeadPose() const; Rotations getHeadPose() const;
Rotations getBodyPose() const; Rotations getBodyPose() const;
@ -82,52 +91,75 @@ public:
void setLeftLegPose (const Rotations& r); void setLeftLegPose (const Rotations& r);
void setRightLegPose(const Rotations& r); void setRightLegPose(const Rotations& r);
virtual bool useNewAi() override { return false; } virtual bool useNewAi() override { return false; }
virtual void tick() override; virtual void tick() override;
virtual bool hurt(DamageSource* source, float damage) override; virtual bool hurt(DamageSource* source, float damage) override;
virtual bool interact(shared_ptr<Player> player) override;
virtual bool isPickable() override; virtual bool isPickable() override;
virtual bool isPushable() override { return false; } virtual bool isPushable() override;
virtual void push(shared_ptr<Entity> entity) override {}
virtual void push(double xa, double ya, double za) override {}
bool ignoreExplosion();
void kill();
virtual bool isAttackable() override { return true; } virtual bool isAttackable() override { return true; }
virtual bool isBaby() override { return isSmall(); }
virtual bool shouldShowName() override { return false; } virtual bool shouldShowName() override { return false; }
virtual wstring getAName() override { return L""; }
virtual wstring getDisplayName() override { return L""; }
virtual wstring getNetworkName() override { return L""; }
virtual bool isInWall() override { return false; } virtual bool isInWall() override { return false; }
virtual shared_ptr<ItemInstance> getCarriedItem() override; virtual float getEyeHeight() override;
virtual shared_ptr<ItemInstance> getCarried(int slot) override;
virtual shared_ptr<ItemInstance> getArmor(int pos) override;
virtual void setEquippedSlot(int slot, shared_ptr<ItemInstance> item) override;
virtual ItemInstanceArray getEquipmentSlots() override;
virtual void readAdditionalSaveData(CompoundTag *tag) override; virtual bool shouldRenderAtSqrDistance(double distSq) override;
virtual void addAdditonalSaveData(CompoundTag *tag) override;
virtual void handleEntityEvent(byte eventId) override;
virtual bool updateInWaterState() override; virtual void push(shared_ptr<Entity> entity) override {}
virtual void push(double xa, double ya, double za) override {}
virtual void pushEntities() override;
protected:
virtual void defineSynchedData() override; virtual void doPush(shared_ptr<Entity> e) override {}
virtual void registerAttributes() override;
virtual int getHurtSound() override { return -1; } virtual int getHurtSound() override { return -1; }
virtual int getDeathSound() override { return -1; } virtual int getDeathSound() override { return -1; }
virtual float getSoundVolume() override { return 0.0f; } virtual float getSoundVolume() override { return 0.0f; }
virtual bool makeStepSound() override { return false; } virtual bool makeStepSound() override { return false; }
private: virtual wstring getAName() override { return L""; }
byte setBit(byte oldBit, int offset, bool value); virtual wstring getDisplayName() override { return L""; }
Rotations readRotation(int slotX) const; virtual wstring getNetworkName() override { return L""; }
void writeRotation(int slotX, const Rotations &r);
virtual bool interact(shared_ptr<Player> player) override;
virtual bool interactAt(shared_ptr<Player> player, const Vec3& hitVec);
virtual int test_interactAt(shared_ptr<Player> player, const Vec3& hitVec);
void brokenByAnything();
void brokenByPlayer(shared_ptr<Player> player, DamageSource* source);
void causeDamage(float damage);
void updateBoundingBox(bool markerMode);
void updateInvisibilityStatus();
virtual shared_ptr<ItemInstance> getCarriedItem() override;
virtual shared_ptr<ItemInstance> getCarried(int slot) override;
virtual shared_ptr<ItemInstance> getArmor(int pos) override;
virtual void setEquippedSlot(int slot, shared_ptr<ItemInstance> item) override;
virtual ItemInstanceArray getEquipmentSlots() override;
bool setSlot(int inventorySlot, shared_ptr<ItemInstance> item);
void swapItem(shared_ptr<Player> player, int slot);
int getEquipmentSlotForItem(shared_ptr<ItemInstance> item) const; int getEquipmentSlotForItem(shared_ptr<ItemInstance> item) const;
bool isSlotDisabled(int slot) const;
shared_ptr<ItemInstance> getItemInSlot(int slot); virtual void readAdditionalSaveData(CompoundTag* tag) override;
virtual void addAdditonalSaveData (CompoundTag* tag) override;
void readPose(CompoundTag* poseTag);
CompoundTag* writePose();
virtual void handleEntityEvent(byte eventId) override;
protected:
virtual void defineSynchedData() override;
virtual void registerAttributes() override;
private:
void init();
}; };

View file

@ -7,6 +7,27 @@
#include "Mth.h" #include "Mth.h"
#include "ArmorStandItem.h" #include "ArmorStandItem.h"
#include "..\Minecraft.World\ArmorStand.h" #include "..\Minecraft.World\ArmorStand.h"
#include "..\Minecraft.World\Entity.h"
ArmorStandItem::ArmorStandItem(int id) : Item(id)
{
maxStackSize = 16;
}
void ArmorStandItem::randomizePose(shared_ptr<ArmorStand> stand, Random *rng)
{
Rotations head = stand->getHeadPose();
float newX = head.getX() + rng->nextFloat() * 5.0f;
float newY = head.getY() + (rng->nextFloat() * 20.0f - 10.0f);
stand->setBodyPose(Rotations(newX, newY, head.getZ()));
Rotations body = stand->getBodyPose();
float bodyY = body.getY() + (rng->nextFloat() * 10.0f - 5.0f);
stand->setBodyPose(Rotations(body.getX(), bodyY, body.getZ()));
}
bool ArmorStandItem::useOn(shared_ptr<ItemInstance> itemInstance, shared_ptr<Player> player, bool ArmorStandItem::useOn(shared_ptr<ItemInstance> itemInstance, shared_ptr<Player> player,
Level *level, int x, int y, int z, int face, Level *level, int x, int y, int z, int face,
@ -18,20 +39,15 @@ bool ArmorStandItem::useOn(shared_ptr<ItemInstance> itemInstance, shared_ptr<Pla
int py = y; int py = y;
int pz = z; int pz = z;
if (face == 0) py--; // bottom if (face == 0) py--;
if (face == 1) py++; // top if (face == 1) py++;
if (face == 2) pz--; // North if (face == 2) pz--;
if (face == 3) pz++; // South if (face == 3) pz++;
if (face == 4) px--; // West if (face == 4) px--;
if (face == 5) px++; // East if (face == 5) px++;
//if (face != 1) return false;
if (level->getTile(px, py, pz) != 0) return false; if (level->getTile(px, py, pz) != 0) return false;
if (level->getTile(px, py + 1, pz) != 0) return false; if (level->getTile(px, py + 1, pz) != 0) return false;
if (bTestUseOnOnly) return true; if (bTestUseOnOnly) return true;
if (level->isClientSide) return true; if (level->isClientSide) return true;
@ -39,7 +55,7 @@ bool ArmorStandItem::useOn(shared_ptr<ItemInstance> itemInstance, shared_ptr<Pla
float targetRot = player->yRot + 180.0f; float targetRot = player->yRot + 180.0f;
float snapped = (float)(Mth::floor((targetRot + 22.5f) / 45.0f) * 45.0f); float snapped = (float)(Mth::floor((targetRot + 22.5f) / 45.0f) * 45.0f);
shared_ptr<ArmorStand> stand = std::make_shared<ArmorStand>(level); auto stand = std::make_shared<ArmorStand>(level);
stand->moveTo(px + 0.5, py, pz + 0.5, snapped, 0.0f); stand->moveTo(px + 0.5, py, pz + 0.5, snapped, 0.0f);
stand->yRot = snapped; stand->yRot = snapped;
stand->yBodyRot = snapped; stand->yBodyRot = snapped;
@ -47,7 +63,6 @@ bool ArmorStandItem::useOn(shared_ptr<ItemInstance> itemInstance, shared_ptr<Pla
stand->yRotO = snapped; stand->yRotO = snapped;
stand->yBodyRotO = snapped; stand->yBodyRotO = snapped;
stand->yHeadRotO = snapped; stand->yHeadRotO = snapped;
level->addEntity(stand); level->addEntity(stand);
if (!player->abilities.instabuild) if (!player->abilities.instabuild)

View file

@ -1,14 +1,19 @@
#pragma once #pragma once
#include "Item.h" #include "Item.h"
#include "ArmorStand.h"
class ArmorStandItem : public Item class ArmorStandItem : public Item
{ {
public: public:
ArmorStandItem(int id) : Item(id) { maxStackSize = 16; } explicit ArmorStandItem(int id);
virtual ~ArmorStandItem() {} virtual ~ArmorStandItem() {}
virtual bool useOn(shared_ptr<ItemInstance> itemInstance, shared_ptr<Player> player, virtual bool useOn(shared_ptr<ItemInstance> itemInstance,
shared_ptr<Player> player,
Level *level, int x, int y, int z, int face, Level *level, int x, int y, int z, int face,
float clickX, float clickY, float clickZ, float clickX, float clickY, float clickZ,
bool bTestUseOnOnly = false) override; bool bTestUseOnOnly = false) override;
static void randomizePose(shared_ptr<ArmorStand> stand, Random *rng);
}; };

View file

@ -10,6 +10,7 @@
#include "StringTag.h" #include "StringTag.h"
#include "ByteArrayTag.h" #include "ByteArrayTag.h"
#include "IntArrayTag.h" #include "IntArrayTag.h"
#include "CompoundContainer.h"
class CompoundTag : public Tag class CompoundTag : public Tag
{ {
@ -143,6 +144,28 @@ public:
{ {
return tags.find(name) != tags.end(); return tags.find(name) != tags.end();
} }
bool contains(const wstring& name, int typeId)
{
auto it = tags.find(name);
if (it != tags.end())
{
int foundType = it->second->getId();
if (foundType == typeId)
return true;
if (typeId == 99)
return (unsigned int)(foundType - 1) <= 5;
return false;
}
else
{
return typeId == 0;
}
}
byte getByte(const wstring &name) byte getByte(const wstring &name)
{ {
@ -200,8 +223,11 @@ public:
CompoundTag* getCompound(const wstring& name) CompoundTag* getCompound(const wstring& name)
{ {
if (tags.find(name) == tags.end()) return new CompoundTag(name); if (contains(name, Tag::TAG_Compound))
return static_cast<CompoundTag *>(tags[name]); {
return static_cast<CompoundTag*>(get(name));
}
return new CompoundTag(name);
} }
ListTag<Tag> *getList(const wstring &name) ListTag<Tag> *getList(const wstring &name)
@ -297,4 +323,8 @@ public:
} }
return false; return false;
} }
}; };

View file

@ -111,6 +111,9 @@ bool DamageSource::isBypassInvul()
return _bypassInvul; return _bypassInvul;
} }
bool DamageSource::isBypassMagic() {
return _bypassInvul;
}
//DamageSource::DamageSource(const wstring &msgId) //DamageSource::DamageSource(const wstring &msgId)
DamageSource::DamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId) DamageSource::DamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId)
@ -214,6 +217,33 @@ bool DamageSource::isFire()
{ {
return isFireSource; return isFireSource;
} }
bool DamageSource::isFireProjectile() {
return _isProjectile;
}
DamageSource* DamageSource::setIsFireProjectile() {
_isProjectile = true;
return this;
}
bool DamageSource::isCreativePlayer() const
{
shared_ptr<Entity> entity = const_cast<DamageSource*>(this)->getEntity();
if (entity != nullptr)
{
shared_ptr<Player> player = dynamic_pointer_cast<Player>(entity);
if (player != nullptr)
{
return player->abilities.instabuild;
}
}
return false;
}
ChatPacket::EChatPacketMessage DamageSource::getMsgId() ChatPacket::EChatPacketMessage DamageSource::getMsgId()
{ {

View file

@ -1,4 +1,6 @@
#pragma once #pragma once
#include <memory>
#include "ChatPacket.h"
using namespace std; using namespace std;
class LivingEntity; class LivingEntity;
@ -8,11 +10,10 @@ class Fireball;
class Player; class Player;
class Explosion; class Explosion;
#include "ChatPacket.h"
class DamageSource class DamageSource
{ {
public: public:
static DamageSource *inFire; static DamageSource *inFire;
static DamageSource *onFire; static DamageSource *onFire;
static DamageSource *lava; static DamageSource *lava;
@ -37,64 +38,77 @@ public:
static DamageSource *indirectMagic(shared_ptr<Entity> entity, shared_ptr<Entity> owner); static DamageSource *indirectMagic(shared_ptr<Entity> entity, shared_ptr<Entity> owner);
static DamageSource *thorns(shared_ptr<Entity> source); static DamageSource *thorns(shared_ptr<Entity> source);
static DamageSource *explosion(Explosion *explosion); static DamageSource *explosion(Explosion *explosion);
private: private:
bool _bypassArmor; bool _bypassArmor;
bool _bypassInvul; bool _bypassInvul;
// food exhastion caused by being damaged by this source
float exhaustion; float exhaustion;
bool isFireSource; bool isFireSource;
bool _isProjectile; bool _isProjectile;
bool _scalesWithDifficulty; bool _scalesWithDifficulty;
bool _isMagic; bool _isMagic;
bool _isExplosion; bool _isExplosion;
bool _isCritical; bool _isCritical;
public: public:
bool isCritical(); ChatPacket::EChatPacketMessage m_msgId;
DamageSource *setIsCritical();
bool isProjectile();
DamageSource *setProjectile();
bool isExplosion();
DamageSource *setExplosion();
bool isBypassArmor(); ChatPacket::EChatPacketMessage m_msgWithItemId;
float getFoodExhaustion();
bool isBypassInvul();
//wstring msgId;
ChatPacket::EChatPacketMessage m_msgId; // 4J Made int so we can localise
ChatPacket::EChatPacketMessage m_msgWithItemId; // 4J: Renamed from m_msgWithSourceId (it was already renamed in places, just made consistent)
protected: protected:
//DamageSource(const wstring &msgId); DamageSource(ChatPacket::EChatPacketMessage msgId,
DamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId = ChatPacket::e_ChatCustom); ChatPacket::EChatPacketMessage msgWithItemId = ChatPacket::e_ChatCustom);
public: public:
virtual ~DamageSource() {} virtual ~DamageSource() {}
virtual shared_ptr<Entity> getDirectEntity(); virtual shared_ptr<Entity> getDirectEntity();
virtual shared_ptr<Entity> getEntity(); virtual shared_ptr<Entity> getEntity();
protected:
DamageSource *bypassArmor();
DamageSource *bypassInvul();
DamageSource *setIsFire();
DamageSource *setScalesWithDifficulty();
public:
virtual bool scalesWithDifficulty(); virtual bool scalesWithDifficulty();
virtual shared_ptr<ChatPacket> getDeathMessagePacket(shared_ptr<LivingEntity> player);
virtual DamageSource *copy();
bool isBypassArmor();
bool isBypassInvul();
bool isBypassMagic();
bool isFire();
DamageSource *setIsFire();
bool isFireProjectile();
DamageSource *setIsFireProjectile();
bool isProjectile();
DamageSource *setProjectile();
bool isMagic(); bool isMagic();
DamageSource *setMagic(); DamageSource *setMagic();
// 4J Stu - Made return a packet bool isExplosion();
//virtual wstring getLocalizedDeathMessage(shared_ptr<Player> player); DamageSource *setExplosion();
virtual shared_ptr<ChatPacket> getDeathMessagePacket(shared_ptr<LivingEntity> player);
bool isFire(); bool isCritical();
ChatPacket::EChatPacketMessage getMsgId(); // 4J Stu - Used to return String DamageSource *setIsCritical();
// 4J Added bool isCreativePlayer() const;
float getFoodExhaustion();
ChatPacket::EChatPacketMessage getMsgId();
bool equals(DamageSource *source); bool equals(DamageSource *source);
virtual DamageSource *copy();
protected:
DamageSource *bypassArmor();
DamageSource *bypassInvul();
DamageSource *setScalesWithDifficulty();
}; };

View file

@ -1,4 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "com.mojang.nbt.h" #include "com.mojang.nbt.h"
#include "net.minecraft.world.item.h" #include "net.minecraft.world.item.h"
#include "net.minecraft.world.item.enchantment.h" #include "net.minecraft.world.item.enchantment.h"
@ -2151,3 +2151,224 @@ unsigned int Entity::getAnimOverrideBitmask()
return m_uiAnimOverrideBitmask; return m_uiAnimOverrideBitmask;
} }
float Entity::getEyeHeight()
{
return bbHeight * 0.85f;
}
bool Entity::ignoreExplosion()
{
return false;
}
void Entity::kill()
{
remove();
}
static const int DATA_CUSTOM_NAME_ID = 2;
static const int DATA_CUSTOM_NAME_VISIBLE_ID = 3;
bool Entity::hasCustomName()
{
if (!entityData) return false;
return !entityData->getString(DATA_CUSTOM_NAME_ID).empty();
}
wstring Entity::getCustomName()
{
if (!entityData) return L"";
return entityData->getString(DATA_CUSTOM_NAME_ID);
}
void Entity::setCustomName(const wstring& name)
{
if (entityData)
entityData->set(DATA_CUSTOM_NAME_ID, name);
}
bool Entity::isCustomNameVisible()
{
if (!entityData) return false;
return entityData->getByte(DATA_CUSTOM_NAME_VISIBLE_ID) == 1;
}
void Entity::setCustomNameVisible(bool visible)
{
if (entityData)
entityData->set(DATA_CUSTOM_NAME_VISIBLE_ID, static_cast<byte>(visible ? 1 : 0));
}
bool Entity::isOutsideWorldBorder()
{
return m_outsideWorldBorder;
}
void Entity::setOutsideWorldBorder(bool outside)
{
m_outsideWorldBorder = outside;
}
int Entity::getDirection()
{
int raw = (int)Mth::floor(yRot * 4.0f / 360.0f + 0.5f) & 3;
switch (raw & 3)
{
case 0: return 2; // South
case 1: return 3; // West
case 2: return 0; // North
case 3: return 1; // East
default: return 0;
}
}
Vec3* Entity::getEyePosition(float partialTicks)
{
if (partialTicks == 1.0f)
{
return Vec3::newTemp(x, y + getEyeHeight(), z);
}
double ix = xo + (x - xo) * partialTicks;
double iy = yo + (y - yo) * partialTicks;
double iz = zo + (z - zo) * partialTicks;
return Vec3::newTemp(ix, iy + getEyeHeight(), iz);
}
bool Entity::isInvulnerableTo(DamageSource* source)
{
if (!entityData) return false;
bool netInvuln = (entityData->getByte(DATA_SHARED_FLAGS_ID) >> 2 & 1) != 0;
if (!netInvuln) return false;
if (source->isCreativePlayer()) return false;
return true;
}
void Entity::setInvulnerable(bool value)
{
setSharedFlag(2, value);
}
wstring Entity::getName()
{
if (hasCustomName())
return getCustomName();
return getAName();
}
void Entity::doSprintParticleEffect()
{
int xt = Mth::floor(x);
int yt = Mth::floor(y - 0.2 - heightOffset);
int zt = Mth::floor(z);
int t = level->getTile(xt, yt, zt);
int d = level->getData(xt, yt, zt);
if (t > 0)
{
AABB* box = getBoundingBox();
level->addParticle(
PARTICLE_TILECRACK(t, d),
x + (random->nextFloat() - 0.5) * bbWidth,
box->y0 + 0.1,
z + (random->nextFloat() - 0.5) * bbWidth,
-(xd * 4.0),
1.5,
-(zd * 4.0));
}
}
bool Entity::shouldShowName()
{
return isCustomNameVisible();
}
int Entity::getPortalEntranceOffset()
{
return portalTime;
}
int Entity::getPortalEntranceForwards()
{
return portalEntranceDir;
}
void Entity::getPortalEntranceBlock(int& ox, int& oy, int& oz)
{
ox = Mth::floor(x);
oy = Mth::floor(y);
oz = Mth::floor(z);
}
Vec3* Entity::getCommandSenderWorldPosition()
{
return Vec3::newTemp(x, y, z);
}
Level* Entity::getCommandSenderWorld()
{
return level;
}
shared_ptr<Entity> Entity::getCommandSenderEntity()
{
return shared_from_this();
}
double Entity::distanceSqrToBlockPosCenter(int bx, int by, int bz)
{
double dx = x - (bx + 0.5);
double dy = y - (by + 0.5);
double dz = z - (bz + 0.5);
return dx*dx + dy*dy + dz*dz;
}
double Entity::distanceSqrToBlockPosCenter(BlockPos* pos)
{
return distanceSqrToBlockPosCenter(pos->getX(), pos->getY(), pos->getZ());
}
void Entity::getSkinAdjustments(struct _SkinAdjustments* adj)
{
if (app.GetGameSettings((eGameSetting)0x18) || (this->m_skinAdjustments.data[17] & 0x1F1F810) != 0)
{
*adj = this->m_skinAdjustments;
}
else
{
*adj = _SkinAdjustments();
}
}
void Entity::setSkinAdjustments(struct _SkinAdjustments* adj)
{
this->m_skinAdjustments = *adj;
}

View file

@ -18,6 +18,7 @@ class Level;
class CompoundTag; class CompoundTag;
class DamageSource; class DamageSource;
class Explosion; class Explosion;
class BlockPos;
// 4J Stu Added this mainly to allow is to record telemetry for player deaths // 4J Stu Added this mainly to allow is to record telemetry for player deaths
enum EEntityDamageType enum EEntityDamageType
@ -31,6 +32,10 @@ enum EEntityDamageType
eEntityDamageType_OutOfWorld, eEntityDamageType_OutOfWorld,
eEntityDamageType_Cactus, eEntityDamageType_Cactus,
}; };
struct _SkinAdjustments
{
int data[18];
};
class Entity : public enable_shared_from_this<Entity> class Entity : public enable_shared_from_this<Entity>
{ {
@ -48,6 +53,7 @@ public:
private: private:
static int entityCounter; static int entityCounter;
bool m_outsideWorldBorder = false;
public: public:
int entityId; int entityId;
@ -73,6 +79,7 @@ public:
protected: protected:
bool isStuckInWeb; bool isStuckInWeb;
_SkinAdjustments m_skinAdjustments;
public: public:
bool slide; bool slide;
@ -199,7 +206,7 @@ protected:
public: public:
virtual void remove(); virtual void remove();
protected: public:
virtual void setSize(float w, float h); virtual void setSize(float w, float h);
void setPos(EntityPos *pos); void setPos(EntityPos *pos);
void setRot(float yRot, float xRot); void setRot(float yRot, float xRot);
@ -256,6 +263,7 @@ public:
virtual bool updateInWaterState(); virtual bool updateInWaterState();
bool isUnderLiquid(Material *material); bool isUnderLiquid(Material *material);
virtual float getHeadHeight(); virtual float getHeadHeight();
float getEyeHeight();
bool isInLava(); bool isInLava();
void moveRelative(float xa, float za, float speed); void moveRelative(float xa, float za, float speed);
virtual int getLightColor(float a); // 4J - change brought forward from 1.8.2 virtual int getLightColor(float a); // 4J - change brought forward from 1.8.2
@ -434,4 +442,77 @@ public:
virtual void setDespawnProtected() {} virtual void setDespawnProtected() {}
virtual bool couldWander() { return false; } virtual bool couldWander() { return false; }
virtual bool canCreateParticles() { return true; } virtual bool canCreateParticles() { return true; }
bool ignoreExplosion();
void kill();
virtual bool hasCustomName();
virtual wstring getCustomName();
virtual void setCustomName(const wstring& name);
virtual bool isCustomNameVisible();
virtual void setCustomNameVisible(bool visible);
bool isOutsideWorldBorder();
void setOutsideWorldBorder(bool outside);
virtual AABB* getBoundingBox() { return bb; }
virtual void setBoundingBox(AABB* box) { bb = box; }
int getDirection();
Vec3* getEyePosition(float partialTicks);
bool isInvulnerableTo(DamageSource* source);
void setInvulnerable(bool value);
wstring getName();
void doSprintParticleEffect();
virtual int getSwimSplashSound() { return 0xDE; }
virtual int getSwimSound() { return 0xDD; }
virtual void onSyncedDataUpdated() {}
int getPortalEntranceOffset();
int getPortalEntranceForwards();
void getPortalEntranceBlock(int& x, int& y, int& z);
virtual void setYBodyRot() {}
virtual bool broadcastToPlayer() { return true; }
virtual bool shouldShowName();
virtual bool interactAt(shared_ptr<Player> player, const Vec3& hitVec) { return false; }
virtual void handleEntityTag() {}
virtual int getEntityTag() { return 0; }
virtual int setSlot() { return 0; }
Vec3* getCommandSenderWorldPosition();
Level* getCommandSenderWorld();
shared_ptr<Entity> getCommandSenderEntity();
double distanceSqrToBlockPosCenter(int bx, int by, int bz);
double distanceSqrToBlockPosCenter(BlockPos* pos);
void getSkinAdjustments(struct _SkinAdjustments* adj);
void setSkinAdjustments(struct _SkinAdjustments* adj);
}; };

View file

@ -1,23 +1,34 @@

#include "stdafx.h" #include "stdafx.h"
#include "PacketListener.h" #include "PacketListener.h"
#include "LevelParticlesPacket.h" #include "LevelParticlesPacket.h"
#include "../Minecraft.Client/ParticleType.h"
LevelParticlesPacket::LevelParticlesPacket() LevelParticlesPacket::LevelParticlesPacket()
{ {
this->name = L"";
this->x = 0.0f; this->overrideLimiter = false;
this->type = nullptr;
this->count = 0;
this->y = 0.0f; this->y = 0.0f;
this->z = 0.0f; this->paramCount = 0;
this->xDist = 0.0f; this->x = 0.0f;
this->yDist = 0.0f; this->yDist = 0.0f;
this->zDist = 0.0f; this->zDist = 0.0f;
this->z = 0.0f;
this->maxSpeed = 0.0f; this->maxSpeed = 0.0f;
this->count = 0; this->xDist = 0.0f;
this->params = nullptr;
} }
LevelParticlesPacket::LevelParticlesPacket(const wstring &name, float x, float y, float z, float xDist, float yDist, float zDist, float maxSpeed, int count) LevelParticlesPacket::LevelParticlesPacket(const ParticleType* type, bool overrideLimiter,
float x, float y, float z,
float xDist, float yDist, float zDist,
float maxSpeed, int count,
arrayWithLength<int> data)
{ {
this->name = name; this->type = type;
this->overrideLimiter = overrideLimiter;
this->x = x; this->x = x;
this->y = y; this->y = y;
this->z = z; this->z = z;
@ -26,77 +37,83 @@ LevelParticlesPacket::LevelParticlesPacket(const wstring &name, float x, float y
this->zDist = zDist; this->zDist = zDist;
this->maxSpeed = maxSpeed; this->maxSpeed = maxSpeed;
this->count = count; this->count = count;
this->paramCount = data.length;
if (data.data && data.length > 0)
{
this->params = new int[data.length];
memcpy(this->params, data.data, data.length * sizeof(int));
}
else
{
this->params = nullptr;
}
}
LevelParticlesPacket::~LevelParticlesPacket()
{
if (params)
{
delete[] params;
params = nullptr;
}
} }
void LevelParticlesPacket::read(DataInputStream* dis) void LevelParticlesPacket::read(DataInputStream* dis)
{ {
name = readUtf(dis, 64); int particleId = dis->readInt();
x = dis->readFloat(); const ParticleType* resolved = ParticleType::byId(particleId);
y = dis->readFloat(); if (!resolved)
z = dis->readFloat(); resolved = ParticleType::getDefault();
xDist = dis->readFloat(); this->type = resolved;
yDist = dis->readFloat();
zDist = dis->readFloat(); this->overrideLimiter = dis->readBoolean();
maxSpeed = dis->readFloat();
count = dis->readInt(); this->x = dis->readFloat();
this->y = dis->readFloat();
this->z = dis->readFloat();
this->xDist = dis->readFloat();
this->yDist = dis->readFloat();
this->zDist = dis->readFloat();
this->maxSpeed = dis->readFloat();
this->count = dis->readInt();
int paramCount = this->type ? this->type->getParamCount() : 0;
this->paramCount = paramCount;
if (paramCount > 0)
{
this->params = new int[paramCount]();
for (int i = 0; i < paramCount; i++)
{
this->params[i] = dis->readInt();
}
}
else
{
this->params = nullptr;
}
} }
void LevelParticlesPacket::write(DataOutputStream* dos) void LevelParticlesPacket::write(DataOutputStream* dos)
{ {
writeUtf(name, dos); dos->writeInt(this->type ? this->type->getId() : 0);
dos->writeFloat(x); dos->writeBoolean(this->overrideLimiter);
dos->writeFloat(y); dos->writeFloat(this->x);
dos->writeFloat(z); dos->writeFloat(this->y);
dos->writeFloat(xDist); dos->writeFloat(this->z);
dos->writeFloat(yDist); dos->writeFloat(this->xDist);
dos->writeFloat(zDist); dos->writeFloat(this->yDist);
dos->writeFloat(maxSpeed); dos->writeFloat(this->zDist);
dos->writeInt(count); dos->writeFloat(this->maxSpeed);
} dos->writeInt(this->count);
wstring LevelParticlesPacket::getName() int toWrite = this->type ? this->type->getParamCount() : 0;
for (int i = 0; i < toWrite; i++)
{ {
return name; dos->writeInt(this->params[i]);
} }
double LevelParticlesPacket::getX()
{
return x;
}
double LevelParticlesPacket::getY()
{
return y;
}
double LevelParticlesPacket::getZ()
{
return z;
}
float LevelParticlesPacket::getXDist()
{
return xDist;
}
float LevelParticlesPacket::getYDist()
{
return yDist;
}
float LevelParticlesPacket::getZDist()
{
return zDist;
}
float LevelParticlesPacket::getMaxSpeed()
{
return maxSpeed;
}
int LevelParticlesPacket::getCount()
{
return count;
} }
void LevelParticlesPacket::handle(PacketListener* listener) void LevelParticlesPacket::handle(PacketListener* listener)
@ -106,5 +123,5 @@ void LevelParticlesPacket::handle(PacketListener *listener)
int LevelParticlesPacket::getEstimatedSize() int LevelParticlesPacket::getEstimatedSize()
{ {
return 4 * 2 + 7 * 8; return 0x40;
} }

View file

@ -1,11 +1,13 @@
#pragma once
#pragma once
#include "Packet.h" #include "Packet.h"
#include "../Minecraft.Client/ParticleType.h"
class LevelParticlesPacket : public Packet, public enable_shared_from_this<LevelParticlesPacket> class LevelParticlesPacket : public Packet, public enable_shared_from_this<LevelParticlesPacket>
{ {
private: private:
wstring name;
const ParticleType* type;
float x; float x;
float y; float y;
float z; float z;
@ -14,26 +16,38 @@ private:
float zDist; float zDist;
float maxSpeed; float maxSpeed;
int count; int count;
bool overrideLimiter;
int* params;
int paramCount;
public: public:
LevelParticlesPacket(); LevelParticlesPacket();
LevelParticlesPacket(const wstring &name, float x, float y, float z, float xDist, float yDist, float zDist, float maxSpeed, int count); LevelParticlesPacket(const ParticleType* type, bool overrideLimiter,
float x, float y, float z,
float xDist, float yDist, float zDist,
float maxSpeed, int count,
arrayWithLength<int> data);
~LevelParticlesPacket();
void read(DataInputStream *dis); void read(DataInputStream* dis) override;
void write(DataOutputStream *dos); void write(DataOutputStream* dos) override;
wstring getName();
double getX(); const ParticleType* getType() { return type; }
double getY(); double getX() { return x; }
double getZ(); double getY() { return y; }
float getXDist(); double getZ() { return z; }
float getYDist(); double getXDist() { return xDist; }
float getZDist(); double getYDist() { return yDist; }
float getMaxSpeed(); double getZDist() { return zDist; }
int getCount(); double getMaxSpeed() { return maxSpeed; }
void handle(PacketListener *listener); int getCount() { return count; }
int getEstimatedSize(); bool isOverrideLimiter() { return overrideLimiter; }
int* getParams() { return params; }
int getParamCount() { return paramCount; }
void handle(PacketListener* listener) override;
int getEstimatedSize() override;
public:
static shared_ptr<Packet> create() { return std::make_shared<LevelParticlesPacket>(); } static shared_ptr<Packet> create() { return std::make_shared<LevelParticlesPacket>(); }
virtual int getId() { return 63; } virtual int getId() override { return 63; }
}; };

View file

@ -7,6 +7,7 @@ GameType *GameType::NOT_SET = nullptr;
GameType *GameType::SURVIVAL= nullptr; GameType *GameType::SURVIVAL= nullptr;
GameType *GameType::CREATIVE = nullptr; GameType *GameType::CREATIVE = nullptr;
GameType *GameType::ADVENTURE = nullptr; GameType *GameType::ADVENTURE = nullptr;
GameType* GameType::SPECTATOR = nullptr;
void GameType::staticCtor() void GameType::staticCtor()
{ {
@ -14,6 +15,7 @@ void GameType::staticCtor()
SURVIVAL = new GameType(0, L"survival"); SURVIVAL = new GameType(0, L"survival");
CREATIVE = new GameType(1, L"creative"); CREATIVE = new GameType(1, L"creative");
ADVENTURE = new GameType(2, L"adventure"); ADVENTURE = new GameType(2, L"adventure");
SPECTATOR = new GameType(3, L"spectator");
} }
GameType::GameType(int id, const wstring &name) GameType::GameType(int id, const wstring &name)
@ -59,6 +61,10 @@ bool GameType::isCreative()
{ {
return this == CREATIVE; return this == CREATIVE;
} }
bool GameType::isSpectator()
{
return this == SPECTATOR;
}
bool GameType::isSurvival() bool GameType::isSurvival()
{ {

View file

@ -14,6 +14,7 @@ public:
static GameType *SURVIVAL; static GameType *SURVIVAL;
static GameType *CREATIVE; static GameType *CREATIVE;
static GameType *ADVENTURE; static GameType *ADVENTURE;
static GameType *SPECTATOR;
static void staticCtor(); static void staticCtor();
@ -30,6 +31,7 @@ public:
bool isAdventureRestricted(); bool isAdventureRestricted();
bool isCreative(); bool isCreative();
bool isSurvival(); bool isSurvival();
bool isSpectator();
static GameType *byId(int id); static GameType *byId(int id);
static GameType *byName(const wstring &name); static GameType *byName(const wstring &name);
}; };

View file

@ -46,6 +46,7 @@ public:
} }
} }
byte getId() { return TAG_List; } byte getId() { return TAG_List; }
wstring toString() wstring toString()
@ -148,4 +149,7 @@ public:
} }
return false; return false;
} }
}; };

View file

@ -2051,7 +2051,7 @@ HitResult *LivingEntity::pick(double range, float a)
return level->clip(from, to); return level->clip(from, to);
} }
bool LivingEntity::isEffectiveAi() bool LivingEntity::isEffectiveAi()const
{ {
return !level->isClientSide; return !level->isClientSide;
} }

View file

@ -24,7 +24,7 @@ protected:
// 4J - added for common ctor code // 4J - added for common ctor code
void _init(); void _init();
public: public:
// 4J-PB - added to replace (e instanceof Type), avoiding dynamic casts
eINSTANCEOF GetType() { return eTYPE_LIVINGENTITY; } eINSTANCEOF GetType() { return eTYPE_LIVINGENTITY; }
static Entity* create(Level* level) { return nullptr; } static Entity* create(Level* level) { return nullptr; }
@ -308,7 +308,7 @@ public:
virtual float getAttackAnim(float a); virtual float getAttackAnim(float a);
virtual Vec3* getPos(float a); virtual Vec3* getPos(float a);
virtual HitResult* pick(double range, float a); virtual HitResult* pick(double range, float a);
virtual bool isEffectiveAi(); virtual bool isEffectiveAi()const;
virtual bool isPickable(); virtual bool isPickable();
virtual bool isPushable(); virtual bool isPushable();
@ -331,4 +331,5 @@ public:
virtual float getEyeHeight(); virtual float getEyeHeight();
virtual Vec3* getPositionEyes(float partialTicks); virtual Vec3* getPositionEyes(float partialTicks);
virtual HitResult* rayTrace(double blockReachDistance, float partialTicks); virtual HitResult* rayTrace(double blockReachDistance, float partialTicks);
}; };

View file

@ -2794,6 +2794,47 @@ unsigned int Player::getPlayerGamePrivilege(unsigned int uiGamePrivileges, EPlay
return 0; return 0;
} }
_SkinAdjustments Player::getSkinAdjustmentsById(unsigned int skinId)
{
_SkinAdjustments adj = _SkinAdjustments();
if ((int)skinId < 0)
{
app.GetSkinAdjustments(&adj, skinId);
unsigned int rawId = skinId & 0x7FFFFFFF;
if (rawId == 2 || rawId == 3 || rawId == 0xC8 || rawId == 0xC9 ||
rawId == 0x194 || rawId == 0x195 || rawId == 0x1F8 || rawId == 0x220 ||
rawId == 0x23A || rawId == 0x23D || rawId == 0x247)
{
adj.data[17] = 2;
}
else if (rawId == 0x1F4)
{
adj.data[17] = 5;
}
else if (rawId == 0x1FA)
{
adj.data[17] = 6;
}
}
return adj;
}
void Player::setPlayerGamePrivilege(EPlayerGamePrivileges privilege, unsigned int value) void Player::setPlayerGamePrivilege(EPlayerGamePrivileges privilege, unsigned int value)
{ {
Player::setPlayerGamePrivilege(m_uiGamePrivileges,privilege,value); Player::setPlayerGamePrivilege(m_uiGamePrivileges,privilege,value);
@ -3204,3 +3245,8 @@ void Player::SetPlayerNameValidState(bool bState)
} }
} }
#endif #endif
bool Player::isSpectator()
{
return false;
}

View file

@ -503,6 +503,7 @@ private:
unsigned int getPlayerGamePrivilege(EPlayerGamePrivileges privilege); unsigned int getPlayerGamePrivilege(EPlayerGamePrivileges privilege);
public: public:
static _SkinAdjustments getSkinAdjustmentsById(unsigned int skinId);
unsigned int getAllPlayerGamePrivileges() { return getPlayerGamePrivilege(ePlayerGamePrivilege_All); } unsigned int getAllPlayerGamePrivileges() { return getPlayerGamePrivilege(ePlayerGamePrivilege_All); }
static unsigned int getPlayerGamePrivilege(unsigned int uiGamePrivileges, EPlayerGamePrivileges privilege); static unsigned int getPlayerGamePrivilege(unsigned int uiGamePrivileges, EPlayerGamePrivileges privilege);
@ -522,6 +523,7 @@ public:
bool hasInvisiblePrivilege(); bool hasInvisiblePrivilege();
bool hasInvulnerablePrivilege(); bool hasInvulnerablePrivilege();
bool isModerator(); bool isModerator();
bool isSpectator();
static void enableAllPlayerPrivileges(unsigned int &uigamePrivileges, bool enable); static void enableAllPlayerPrivileges(unsigned int &uigamePrivileges, bool enable);
void enableAllPlayerPrivileges(bool enable); void enableAllPlayerPrivileges(bool enable);

View file

@ -0,0 +1,22 @@
#include "stdafx.h"
#include "Rotations.h"
#include "ListTag.h"
#include "FloatTag.h"
Rotations::Rotations(ListTag<FloatTag>* list)
{
x = list->get(0)->data;
y = list->get(1)->data;
z = list->get(2)->data;
}
ListTag<FloatTag>* Rotations::save() const
{
ListTag<FloatTag>* tag = new ListTag<FloatTag>();
tag->add(new FloatTag(L"", x));
tag->add(new FloatTag(L"", y));
tag->add(new FloatTag(L"", z));
return tag;
}

View file

@ -0,0 +1,44 @@
#pragma once
#include <memory>
using namespace std;
template<class T> class ListTag;
class FloatTag;
class Rotations
{
public:
float x, y, z;
public:
Rotations() : x(0.0f), y(0.0f), z(0.0f) {}
Rotations(float x, float y, float z) : x(x), y(y), z(z) {}
Rotations(const Rotations& other) : x(other.x), y(other.y), z(other.z) {}
Rotations(ListTag<FloatTag>* list);
float getX() const { return x; }
float getY() const { return y; }
float getZ() const { return z; }
bool operator==(const Rotations& other) const
{
return x == other.x && y == other.y && z == other.z;
}
bool operator!=(const Rotations& other) const
{
return !(*this == other);
}
ListTag<FloatTag>* save() const;
};

View file

@ -1,4 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Class.h" #include "Class.h"
#include "BasicTypeContainers.h" #include "BasicTypeContainers.h"
#include "InputOutputStream.h" #include "InputOutputStream.h"
@ -7,20 +7,19 @@
#include "net.minecraft.world.item.h" #include "net.minecraft.world.item.h"
#include "SynchedEntityData.h" #include "SynchedEntityData.h"
SynchedEntityData::SynchedEntityData() SynchedEntityData::SynchedEntityData()
{ {
m_isDirty = false; m_isDirty = false;
m_isEmpty = true; m_isEmpty = true;
} }
void SynchedEntityData::define(int id, int value) void SynchedEntityData::define(int id, int value)
{ {
MemSect(17); MemSect(17);
checkId(id); checkId(id);
int type = TYPE_INT; itemsById[id] = std::make_shared<DataItem>(TYPE_INT, id, value);
shared_ptr<DataItem> dataItem = std::make_shared<DataItem>(type, id, value);
itemsById[id] = dataItem;
MemSect(0); MemSect(0);
m_isEmpty = false; m_isEmpty = false;
} }
@ -29,9 +28,7 @@ void SynchedEntityData::define(int id, byte value)
{ {
MemSect(17); MemSect(17);
checkId(id); checkId(id);
int type = TYPE_BYTE; itemsById[id] = std::make_shared<DataItem>(TYPE_BYTE, id, value);
shared_ptr<DataItem> dataItem = std::make_shared<DataItem>(type, id, value);
itemsById[id] = dataItem;
MemSect(0); MemSect(0);
m_isEmpty = false; m_isEmpty = false;
} }
@ -40,9 +37,7 @@ void SynchedEntityData::define(int id, short value)
{ {
MemSect(17); MemSect(17);
checkId(id); checkId(id);
int type = TYPE_SHORT; itemsById[id] = std::make_shared<DataItem>(TYPE_SHORT, id, value);
shared_ptr<DataItem> dataItem = std::make_shared<DataItem>(type, id, value);
itemsById[id] = dataItem;
MemSect(0); MemSect(0);
m_isEmpty = false; m_isEmpty = false;
} }
@ -51,9 +46,7 @@ void SynchedEntityData::define(int id, float value)
{ {
MemSect(17); MemSect(17);
checkId(id); checkId(id);
int type = TYPE_FLOAT; itemsById[id] = std::make_shared<DataItem>(TYPE_FLOAT, id, value);
shared_ptr<DataItem> dataItem = std::make_shared<DataItem>(type, id, value);
itemsById[id] = dataItem;
MemSect(0); MemSect(0);
m_isEmpty = false; m_isEmpty = false;
} }
@ -62,9 +55,16 @@ void SynchedEntityData::define(int id, const wstring& value)
{ {
MemSect(17); MemSect(17);
checkId(id); checkId(id);
int type = TYPE_STRING; itemsById[id] = std::make_shared<DataItem>(TYPE_STRING, id, value);
shared_ptr<DataItem> dataItem = std::make_shared<DataItem>(type, id, value); MemSect(0);
itemsById[id] = dataItem; m_isEmpty = false;
}
void SynchedEntityData::define(int id, const Rotations& value)
{
MemSect(17);
checkId(id);
itemsById[id] = std::make_shared<DataItem>(TYPE_ROTATIONS, id, value);
MemSect(0); MemSect(0);
m_isEmpty = false; m_isEmpty = false;
} }
@ -73,553 +73,278 @@ void SynchedEntityData::defineNULL(int id, void *pVal)
{ {
MemSect(17); MemSect(17);
checkId(id); checkId(id);
int type = TYPE_ITEMINSTANCE; itemsById[id] = std::make_shared<DataItem>(TYPE_ITEMINSTANCE, id, shared_ptr<ItemInstance>());
shared_ptr<DataItem> dataItem = std::make_shared<DataItem>(type, id, shared_ptr<ItemInstance>());
itemsById[id] = dataItem;
MemSect(0); MemSect(0);
m_isEmpty = false; m_isEmpty = false;
} }
void SynchedEntityData::checkId(int id) void SynchedEntityData::checkId(int id)
{ {
#if 0 // validation disabled in shipping build
if (id > MAX_ID_VALUE)
{
throw new IllegalArgumentException(L"Data value id is too big with " + std::to_wstring(id) + L"! (Max is " + std::to_wstring(MAX_ID_VALUE) + L")");
}
if (itemsById.find(id) != itemsById.end())
{
throw new IllegalArgumentException(L"Duplicate id value for " + std::to_wstring(id) + L"!");
}
#endif
} }
byte SynchedEntityData::getByte(int id)
{
return itemsById[id]->getValue_byte();
}
short SynchedEntityData::getShort(int id)
{
return itemsById[id]->getValue_short();
}
int SynchedEntityData::getInteger(int id) byte SynchedEntityData::getByte(int id) { return itemsById[id]->getValue_byte(); }
{ short SynchedEntityData::getShort(int id) { return itemsById[id]->getValue_short(); }
return itemsById[id]->getValue_int(); int SynchedEntityData::getInteger(int id) { return itemsById[id]->getValue_int(); }
} float SynchedEntityData::getFloat(int id) { return itemsById[id]->getValue_float(); }
wstring SynchedEntityData::getString(int id) { return itemsById[id]->getValue_wstring(); }
float SynchedEntityData::getFloat(int id) shared_ptr<ItemInstance> SynchedEntityData::getItemInstance(int id) { return itemsById[id]->getValue_itemInstance(); }
{
return itemsById[id]->getValue_float();
}
wstring SynchedEntityData::getString(int id)
{
return itemsById[id]->getValue_wstring();
}
shared_ptr<ItemInstance> SynchedEntityData::getItemInstance(int id)
{
//assert(false); // 4J - not currently implemented
return itemsById[id]->getValue_itemInstance();
}
Pos* SynchedEntityData::getPos(int id) Pos* SynchedEntityData::getPos(int id)
{ {
assert(false); // 4J - not currently implemented assert(false);
return nullptr; return nullptr;
} }
Rotations SynchedEntityData::getRotations(int id)
{
return itemsById[id]->getValue_rotations();
}
void SynchedEntityData::set(int id, int value) void SynchedEntityData::set(int id, int value)
{ {
shared_ptr<DataItem> dataItem = itemsById[id]; shared_ptr<DataItem> item = itemsById[id];
if (value != item->getValue_int()) { item->setValue(value); item->setDirty(true); m_isDirty = true; }
// update the value if it has changed
if (value != dataItem->getValue_int())
{
dataItem->setValue(value);
dataItem->setDirty(true);
m_isDirty = true;
}
} }
void SynchedEntityData::set(int id, byte value) void SynchedEntityData::set(int id, byte value)
{ {
shared_ptr<DataItem> dataItem = itemsById[id]; shared_ptr<DataItem> item = itemsById[id];
if (value != item->getValue_byte()) { item->setValue(value); item->setDirty(true); m_isDirty = true; }
// update the value if it has changed
if (value != dataItem->getValue_byte())
{
dataItem->setValue(value);
dataItem->setDirty(true);
m_isDirty = true;
}
} }
void SynchedEntityData::set(int id, short value) void SynchedEntityData::set(int id, short value)
{ {
shared_ptr<DataItem> dataItem = itemsById[id]; shared_ptr<DataItem> item = itemsById[id];
if (value != item->getValue_short()) { item->setValue(value); item->setDirty(true); m_isDirty = true; }
// update the value if it has changed
if (value != dataItem->getValue_short())
{
dataItem->setValue(value);
dataItem->setDirty(true);
m_isDirty = true;
}
} }
void SynchedEntityData::set(int id, float value) void SynchedEntityData::set(int id, float value)
{ {
shared_ptr<DataItem> dataItem = itemsById[id]; shared_ptr<DataItem> item = itemsById[id];
if (value != item->getValue_float()) { item->setValue(value); item->setDirty(true); m_isDirty = true; }
// update the value if it has changed
if (value != dataItem->getValue_float())
{
dataItem->setValue(value);
dataItem->setDirty(true);
m_isDirty = true;
}
} }
void SynchedEntityData::set(int id, const wstring& value) void SynchedEntityData::set(int id, const wstring& value)
{ {
shared_ptr<DataItem> dataItem = itemsById[id]; shared_ptr<DataItem> item = itemsById[id];
if (value != item->getValue_wstring()) { item->setValue(value); item->setDirty(true); m_isDirty = true; }
// update the value if it has changed
if (value != dataItem->getValue_wstring())
{
dataItem->setValue(value);
dataItem->setDirty(true);
m_isDirty = true;
}
} }
void SynchedEntityData::set(int id, shared_ptr<ItemInstance> value) void SynchedEntityData::set(int id, shared_ptr<ItemInstance> value)
{ {
shared_ptr<DataItem> dataItem = itemsById[id]; shared_ptr<DataItem> item = itemsById[id];
if (value != item->getValue_itemInstance()) { item->setValue(value); item->setDirty(true); m_isDirty = true; }
// update the value if it has changed
if (value != dataItem->getValue_itemInstance())
{
dataItem->setValue(value);
dataItem->setDirty(true);
m_isDirty = true;
}
} }
void SynchedEntityData::markDirty(int id) void SynchedEntityData::set(int id, const Rotations& value)
{ {
itemsById[id]->dirty = true; shared_ptr<DataItem> item = itemsById[id];
m_isDirty = true; if (value != item->getValue_rotations()) { item->setValue(value); item->setDirty(true); m_isDirty = true; }
} }
bool SynchedEntityData::isDirty()
{
return m_isDirty;
}
void SynchedEntityData::pack(vector<shared_ptr<DataItem> > *items, DataOutputStream *output) // TODO throws IOException
{
void SynchedEntityData::markDirty(int id) { itemsById[id]->dirty = true; m_isDirty = true; }
bool SynchedEntityData::isDirty() { return m_isDirty; }
bool SynchedEntityData::isEmpty() { return m_isEmpty; }
void SynchedEntityData::clearDirty() { m_isDirty = false; }
void SynchedEntityData::pack(vector<shared_ptr<DataItem>>* items, DataOutputStream* output)
{
if (items) if (items)
{ for (auto& item : *items)
for (auto& dataItem : *items) writeDataItem(output, item);
{
writeDataItem(output, dataItem);
}
}
// add an eof
output->writeByte(EOF_MARKER); output->writeByte(EOF_MARKER);
} }
vector<shared_ptr<SynchedEntityData::DataItem>>* SynchedEntityData::packDirty() vector<shared_ptr<SynchedEntityData::DataItem>>* SynchedEntityData::packDirty()
{ {
vector<shared_ptr<DataItem>>* result = nullptr; vector<shared_ptr<DataItem>>* result = nullptr;
if (m_isDirty) if (m_isDirty)
{ {
for (int i = 0; i <= MAX_ID_VALUE; i++) for (int i = 0; i <= MAX_ID_VALUE; i++)
{ {
shared_ptr<DataItem> dataItem = itemsById[i]; shared_ptr<DataItem> item = itemsById[i];
if ((dataItem != nullptr) && dataItem->isDirty()) if (item && item->isDirty())
{ {
dataItem->setDirty(false); item->setDirty(false);
if (!result) result = new vector<shared_ptr<DataItem>>();
if (result == nullptr) result->push_back(item);
{
result = new vector<shared_ptr<DataItem> >();
}
result->push_back(dataItem);
} }
} }
} }
m_isDirty = false; m_isDirty = false;
return result; return result;
} }
void SynchedEntityData::packAll(DataOutputStream *output) // throws IOException void SynchedEntityData::packAll(DataOutputStream* output)
{ {
for (int i = 0; i <= MAX_ID_VALUE; i++) for (int i = 0; i <= MAX_ID_VALUE; i++)
{ if (itemsById[i]) writeDataItem(output, itemsById[i]);
shared_ptr<DataItem> dataItem = itemsById[i];
if(dataItem != nullptr)
{
writeDataItem(output, dataItem);
}
}
// add an eof
output->writeByte(EOF_MARKER); output->writeByte(EOF_MARKER);
} }
vector<shared_ptr<SynchedEntityData::DataItem>>* SynchedEntityData::getAll() vector<shared_ptr<SynchedEntityData::DataItem>>* SynchedEntityData::getAll()
{ {
vector<shared_ptr<DataItem>>* result = nullptr; vector<shared_ptr<DataItem>>* result = nullptr;
for (int i = 0; i <= MAX_ID_VALUE; i++) for (int i = 0; i <= MAX_ID_VALUE; i++)
{ {
shared_ptr<DataItem> dataItem = itemsById[i]; if (itemsById[i])
if(dataItem != nullptr)
{ {
if (result == nullptr) if (!result) result = new vector<shared_ptr<DataItem>>();
{ result->push_back(itemsById[i]);
result = new vector<shared_ptr<DataItem> >();
}
result->push_back(dataItem);
} }
} }
return result; return result;
} }
void SynchedEntityData::writeDataItem(DataOutputStream* output, shared_ptr<DataItem> item)
void SynchedEntityData::writeDataItem(DataOutputStream *output, shared_ptr<DataItem> dataItem) //throws IOException
{ {
// pack type and id int header = ((item->getType() << TYPE_SHIFT) | (item->getId() & MAX_ID_VALUE)) & 0xff;
int header = ((dataItem->getType() << TYPE_SHIFT) | (dataItem->getId() & MAX_ID_VALUE)) & 0xff;
output->writeByte(header); output->writeByte(header);
switch (item->getType())
// write value
switch (dataItem->getType())
{ {
case TYPE_BYTE: case TYPE_BYTE: output->writeByte(item->getValue_byte()); break;
output->writeByte( dataItem->getValue_byte()); case TYPE_INT: output->writeInt(item->getValue_int()); break;
break; case TYPE_SHORT: output->writeShort(item->getValue_short()); break;
case TYPE_INT: case TYPE_FLOAT: output->writeFloat(item->getValue_float()); break;
output->writeInt( dataItem->getValue_int()); case TYPE_STRING: Packet::writeUtf(item->getValue_wstring(), output); break;
break; case TYPE_ITEMINSTANCE: Packet::writeItem(item->getValue_itemInstance(), output); break;
case TYPE_SHORT: case TYPE_ROTATIONS:
output->writeShort( dataItem->getValue_short()); output->writeFloat(item->getValue_rotations().getX());
break; output->writeFloat(item->getValue_rotations().getY());
case TYPE_FLOAT: output->writeFloat(item->getValue_rotations().getZ());
output->writeFloat( dataItem->getValue_float());
break;
case TYPE_STRING:
Packet::writeUtf(dataItem->getValue_wstring(), output);
break;
case TYPE_ITEMINSTANCE:
{
shared_ptr<ItemInstance> instance = (shared_ptr<ItemInstance> )dataItem->getValue_itemInstance();
Packet::writeItem(instance, output);
}
break;
default:
assert(false); // 4J - not implemented
break; break;
default: assert(false); break;
} }
} }
vector<shared_ptr<SynchedEntityData::DataItem> > *SynchedEntityData::unpack(DataInputStream *input) //throws IOException vector<shared_ptr<SynchedEntityData::DataItem>>* SynchedEntityData::unpack(DataInputStream* input)
{ {
vector<shared_ptr<DataItem>>* result = nullptr; vector<shared_ptr<DataItem>>* result = nullptr;
int currentHeader = input->readByte(); int currentHeader = input->readByte();
int itemCount = 0; int itemCount = 0;
const int MAX_ENTITY_DATA_ITEMS = 256; const int MAX_ENTITY_DATA_ITEMS = 256;
while (currentHeader != EOF_MARKER && itemCount < MAX_ENTITY_DATA_ITEMS) while (currentHeader != EOF_MARKER && itemCount < MAX_ENTITY_DATA_ITEMS)
{ {
if (!result) result = new vector<shared_ptr<DataItem>>();
if (result == nullptr)
{
result = new vector<shared_ptr<DataItem> >();
}
// split type and id
int itemType = (currentHeader & TYPE_MASK) >> TYPE_SHIFT; int itemType = (currentHeader & TYPE_MASK) >> TYPE_SHIFT;
int itemId = (currentHeader & MAX_ID_VALUE); int itemId = (currentHeader & MAX_ID_VALUE);
shared_ptr<DataItem> item;
shared_ptr<DataItem> item = shared_ptr<DataItem>();
switch (itemType) switch (itemType)
{ {
case TYPE_BYTE: case TYPE_BYTE: item = std::make_shared<DataItem>(itemType, itemId, (byte)input->readByte()); break;
case TYPE_SHORT: item = std::make_shared<DataItem>(itemType, itemId, (short)input->readShort()); break;
case TYPE_INT: item = std::make_shared<DataItem>(itemType, itemId, (int)input->readInt()); break;
case TYPE_FLOAT: item = std::make_shared<DataItem>(itemType, itemId, (float)input->readFloat()); break;
case TYPE_STRING: item = std::make_shared<DataItem>(itemType, itemId, Packet::readUtf(input, MAX_STRING_DATA_LENGTH)); break;
case TYPE_ITEMINSTANCE: item = std::make_shared<DataItem>(itemType, itemId, Packet::readItem(input)); break;
case TYPE_ROTATIONS:
{ {
byte dataRead = input->readByte(); float rx = input->readFloat();
item = std::make_shared<DataItem>(itemType, itemId, dataRead); float ry = input->readFloat();
float rz = input->readFloat();
item = std::make_shared<DataItem>(itemType, itemId, Rotations(rx, ry, rz));
break;
} }
break;
case TYPE_SHORT:
{
short dataRead = input->readShort();
item = std::make_shared<DataItem>(itemType, itemId, dataRead);
}
break;
case TYPE_INT:
{
int dataRead = input->readInt();
item = std::make_shared<DataItem>(itemType, itemId, dataRead);
}
break;
case TYPE_FLOAT:
{
float dataRead = input->readFloat();
item = std::make_shared<DataItem>(itemType, itemId, dataRead);
}
break;
case TYPE_STRING:
item = std::make_shared<DataItem>(itemType, itemId, Packet::readUtf(input, MAX_STRING_DATA_LENGTH));
break;
case TYPE_ITEMINSTANCE:
{
item = std::make_shared<DataItem>(itemType, itemId, Packet::readItem(input));
}
break;
default: default:
app.DebugPrintf(" ------ garbage data, or early end of stream due to an incomplete packet\n"); app.DebugPrintf(" ------ garbage data, or early end of stream\n");
delete result; delete result;
return nullptr; return nullptr;
break;
} }
result->push_back(item); result->push_back(item);
itemCount++; itemCount++;
currentHeader = input->readByte(); currentHeader = input->readByte();
} }
return result; return result;
} }
/**
* Assigns values from a list of data items.
*
* @param items
*/
void SynchedEntityData::assignValues(vector<shared_ptr<DataItem>>* items) void SynchedEntityData::assignValues(vector<shared_ptr<DataItem>>* items)
{ {
for (auto& item : *items) for (auto& item : *items)
{ {
shared_ptr<DataItem> itemFromId = itemsById[item->getId()]; shared_ptr<DataItem> dest = itemsById[item->getId()];
if( itemFromId != nullptr ) if (!dest) continue;
{
switch (item->getType()) switch (item->getType())
{ {
case TYPE_BYTE: case TYPE_BYTE: dest->setValue(item->getValue_byte()); break;
itemFromId->setValue(item->getValue_byte()); case TYPE_SHORT: dest->setValue(item->getValue_short()); break;
break; case TYPE_INT: dest->setValue(item->getValue_int()); break;
case TYPE_SHORT: case TYPE_FLOAT: dest->setValue(item->getValue_float()); break;
itemFromId->setValue(item->getValue_short()); case TYPE_STRING: dest->setValue(item->getValue_wstring()); break;
break; case TYPE_ITEMINSTANCE: dest->setValue(item->getValue_itemInstance()); break;
case TYPE_INT: case TYPE_ROTATIONS: dest->setValue(item->getValue_rotations()); break;
itemFromId->setValue(item->getValue_int()); default: assert(false); break;
break;
case TYPE_FLOAT:
itemFromId->setValue(item->getValue_float());
break;
case TYPE_STRING:
itemFromId->setValue(item->getValue_wstring());
break;
case TYPE_ITEMINSTANCE:
itemFromId->setValue(item->getValue_itemInstance());
break;
default:
assert(false); // 4J - not implemented
break;
} }
} }
}
// client-side dirty
m_isDirty = true; m_isDirty = true;
} }
bool SynchedEntityData::isEmpty()
{
return m_isEmpty;
}
void SynchedEntityData::clearDirty()
{
m_isDirty = false;
}
int SynchedEntityData::getSizeInBytes() int SynchedEntityData::getSizeInBytes()
{ {
int size = 1; int size = 1;
for (int i = 0; i <= MAX_ID_VALUE; i++) for (int i = 0; i <= MAX_ID_VALUE; i++)
{ {
shared_ptr<DataItem> dataItem = itemsById[i]; shared_ptr<DataItem> item = itemsById[i];
if(dataItem != nullptr) if (!item) continue;
{
size += 1; size += 1;
switch (item->getType())
// write value
switch (dataItem->getType())
{ {
case TYPE_BYTE: case TYPE_BYTE: size += 1; break;
size += 1; case TYPE_SHORT: size += 2; break;
break; case TYPE_INT: size += 4; break;
case TYPE_SHORT: case TYPE_FLOAT: size += 4; break;
size += 2; case TYPE_STRING: size += (int)item->getValue_wstring().length() + 2; break;
break; case TYPE_ITEMINSTANCE: size += 5; break;
case TYPE_INT: case TYPE_ROTATIONS: size += 12; break;
size += 4; default: break;
break;
case TYPE_FLOAT:
size += 4;
break;
case TYPE_STRING:
size += static_cast<int>(dataItem->getValue_wstring().length()) + 2; // Estimate, assuming all ascii chars
break;
case TYPE_ITEMINSTANCE:
// short + byte + short
size += 2 + 1 + 2; // Estimate, assuming all ascii chars
break;
default:
break;
}
} }
} }
return size; return size;
} }
//////////////////
// DataItem class
/////////////////
SynchedEntityData::DataItem::DataItem(int type, int id, int value) : type( type ), id( id ) SynchedEntityData::DataItem::DataItem(int type, int id, int value) : type(type), id(id) { value_int = value; dirty = true; }
SynchedEntityData::DataItem::DataItem(int type, int id, byte value) : type(type), id(id) { value_byte = value; dirty = true; }
SynchedEntityData::DataItem::DataItem(int type, int id, short value) : type(type), id(id) { value_short = value; dirty = true; }
SynchedEntityData::DataItem::DataItem(int type, int id, float value) : type(type), id(id) { value_float = value; dirty = true; }
SynchedEntityData::DataItem::DataItem(int type, int id, const wstring& value) : type(type), id(id) { value_wstring = value; dirty = true; }
SynchedEntityData::DataItem::DataItem(int type, int id, shared_ptr<ItemInstance> value) : type(type), id(id) { value_itemInstance = value; dirty = true; }
SynchedEntityData::DataItem::DataItem(int type, int id, const Rotations& value)
: type(type), id(id), value_rotations(value)
{ {
this->value_int = value; value_int = 0;
this->dirty = true; dirty = true;
} }
SynchedEntityData::DataItem::DataItem(int type, int id, byte value) : type( type ), id( id ) void SynchedEntityData::DataItem::setValue(const Rotations& value) { value_rotations = value; }
{ Rotations SynchedEntityData::DataItem::getValue_rotations() { return value_rotations; }
this->value_byte = value;
this->dirty = true;
}
SynchedEntityData::DataItem::DataItem(int type, int id, short value) : type( type ), id( id ) int SynchedEntityData::DataItem::getId() { return id; }
{ int SynchedEntityData::DataItem::getType() { return type; }
this->value_short = value; bool SynchedEntityData::DataItem::isDirty() { return dirty; }
this->dirty = true; void SynchedEntityData::DataItem::setDirty(bool d) { dirty = d; }
}
SynchedEntityData::DataItem::DataItem(int type, int id, float value) : type( type ), id( id ) void SynchedEntityData::DataItem::setValue(int v) { value_int = v; }
{ void SynchedEntityData::DataItem::setValue(byte v) { value_byte = v; }
this->value_float = value; void SynchedEntityData::DataItem::setValue(short v) { value_short = v; }
this->dirty = true; void SynchedEntityData::DataItem::setValue(float v) { value_float = v; }
} void SynchedEntityData::DataItem::setValue(const wstring& v) { value_wstring = v; }
void SynchedEntityData::DataItem::setValue(shared_ptr<ItemInstance> v) { value_itemInstance = v; }
SynchedEntityData::DataItem::DataItem(int type, int id, const wstring& value) : type( type ), id( id ) int SynchedEntityData::DataItem::getValue_int() { return value_int; }
{ short SynchedEntityData::DataItem::getValue_short() { return value_short; }
this->value_wstring = value; float SynchedEntityData::DataItem::getValue_float() { return value_float; }
this->dirty = true; byte SynchedEntityData::DataItem::getValue_byte() { return value_byte; }
} wstring SynchedEntityData::DataItem::getValue_wstring() { return value_wstring; }
shared_ptr<ItemInstance> SynchedEntityData::DataItem::getValue_itemInstance() { return value_itemInstance; }
SynchedEntityData::DataItem::DataItem(int type, int id, shared_ptr<ItemInstance> itemInstance) : type( type ), id( id )
{
this->value_itemInstance = itemInstance;
this->dirty = true;
}
int SynchedEntityData::DataItem::getId()
{
return id;
}
void SynchedEntityData::DataItem::setValue(int value)
{
this->value_int = value;
}
void SynchedEntityData::DataItem::setValue(byte value)
{
this->value_byte = value;
}
void SynchedEntityData::DataItem::setValue(short value)
{
this->value_short = value;
}
void SynchedEntityData::DataItem::setValue(float value)
{
this->value_float = value;
}
void SynchedEntityData::DataItem::setValue(const wstring& value)
{
this->value_wstring = value;
}
void SynchedEntityData::DataItem::setValue(shared_ptr<ItemInstance> itemInstance)
{
this->value_itemInstance = itemInstance;
}
int SynchedEntityData::DataItem::getValue_int()
{
return value_int;
}
short SynchedEntityData::DataItem::getValue_short()
{
return value_short;
}
float SynchedEntityData::DataItem::getValue_float()
{
return value_float;
}
byte SynchedEntityData::DataItem::getValue_byte()
{
return value_byte;
}
wstring SynchedEntityData::DataItem::getValue_wstring()
{
return value_wstring;
}
shared_ptr<ItemInstance> SynchedEntityData::DataItem::getValue_itemInstance()
{
return value_itemInstance;
}
int SynchedEntityData::DataItem::getType()
{
return type;
}
bool SynchedEntityData::DataItem::isDirty()
{
return dirty;
}
void SynchedEntityData::DataItem::setDirty(bool dirty)
{
this->dirty = dirty;
}

View file

@ -1,9 +1,9 @@
#pragma once #pragma once
#include "Rotations.h"
using namespace std; using namespace std;
class Pos; class Pos;
class SynchedEntityData class SynchedEntityData
{ {
public: public:
@ -13,8 +13,6 @@ public:
private: private:
const int type; const int type;
const int id; const int id;
// 4J - there used to be one "value" type here of general type Object, just storing the different (used) varieties
// here separately for us
union { union {
byte value_byte; byte value_byte;
int value_int; int value_int;
@ -26,7 +24,12 @@ public:
bool dirty; bool dirty;
public: public:
// There was one type here that took a generic Object type, using overloading here instead Rotations value_rotations;
DataItem(int type, int id, const Rotations& value);
void setValue(const Rotations& value);
Rotations getValue_rotations();
DataItem(int type, int id, byte value); DataItem(int type, int id, byte value);
DataItem(int type, int id, int value); DataItem(int type, int id, int value);
DataItem(int type, int id, const wstring& value); DataItem(int type, int id, const wstring& value);
@ -61,19 +64,15 @@ public:
static const int TYPE_INT = 2; static const int TYPE_INT = 2;
static const int TYPE_FLOAT = 3; static const int TYPE_FLOAT = 3;
static const int TYPE_STRING = 4; static const int TYPE_STRING = 4;
// special types (max possible value is 7):
static const int TYPE_ITEMINSTANCE = 5; static const int TYPE_ITEMINSTANCE = 5;
static const int TYPE_POS = 6; static const int TYPE_POS = 6;
static const int TYPE_ROTATIONS = 7;
private: private:
bool m_isEmpty; bool m_isEmpty;
// must have enough bits to fit the type
private:
static const int TYPE_MASK = 0xe0; static const int TYPE_MASK = 0xe0;
static const int TYPE_SHIFT = 5; static const int TYPE_SHIFT = 5;
// the id value must fit in the remaining bits
static const int MAX_ID_VALUE = ~TYPE_MASK & 0xff; static const int MAX_ID_VALUE = ~TYPE_MASK & 0xff;
shared_ptr<DataItem> itemsById[MAX_ID_VALUE + 1]; shared_ptr<DataItem> itemsById[MAX_ID_VALUE + 1];
@ -82,16 +81,15 @@ private:
public: public:
SynchedEntityData(); SynchedEntityData();
// 4J - this function used to be a template, but there's only 3 varieties of use I've found so just hard-coding now, as
// the original had some automatic Class to type sort of conversion that's a real pain for us to actually do
void define(int id, byte value); void define(int id, byte value);
void define(int id, const wstring& value); void define(int id, const wstring& value);
void define(int id, int value); void define(int id, int value);
void define(int id, short value); void define(int id, short value);
void define(int id, float value); void define(int id, float value);
void define(int id, const Rotations& value);
void defineNULL(int id, void* pVal); void defineNULL(int id, void* pVal);
void checkId(int id); // 4J - added to contain common code from overloaded define functions above void checkId(int id);
byte getByte(int id); byte getByte(int id);
short getShort(int id); short getShort(int id);
int getInteger(int id); int getInteger(int id);
@ -99,33 +97,29 @@ public:
wstring getString(int id); wstring getString(int id);
shared_ptr<ItemInstance> getItemInstance(int id); shared_ptr<ItemInstance> getItemInstance(int id);
Pos* getPos(int id); Pos* getPos(int id);
// 4J - using overloads rather than template here
void set(int id, byte value); void set(int id, byte value);
void set(int id, int value); void set(int id, int value);
void set(int id, short value); void set(int id, short value);
void set(int id, float value); void set(int id, float value);
void set(int id, const wstring& value); void set(int id, const wstring& value);
void set(int id, shared_ptr<ItemInstance>); void set(int id, shared_ptr<ItemInstance>);
void set(int id, const Rotations& value);
Rotations getRotations(int id);
void markDirty(int id); void markDirty(int id);
bool isDirty(); bool isDirty();
static void pack(vector<shared_ptr<DataItem> > *items, DataOutputStream *output); // TODO throws IOException static void pack(vector<shared_ptr<DataItem>>* items, DataOutputStream* output);
vector<shared_ptr<DataItem>>* packDirty(); vector<shared_ptr<DataItem>>* packDirty();
void packAll(DataOutputStream *output); // throws IOException void packAll(DataOutputStream* output);
vector<shared_ptr<DataItem>>* getAll(); vector<shared_ptr<DataItem>>* getAll();
private: private:
static void writeDataItem(DataOutputStream *output, shared_ptr<DataItem> dataItem); //throws IOException static void writeDataItem(DataOutputStream* output, shared_ptr<DataItem> dataItem);
public: public:
static vector<shared_ptr<DataItem> > *unpack(DataInputStream *input); // throws IOException static vector<shared_ptr<DataItem>>* unpack(DataInputStream* input);
/**
* Assigns values from a list of data items.
*
* @param items
*/
public:
void assignValues(vector<shared_ptr<DataItem>>* items); void assignValues(vector<shared_ptr<DataItem>>* items);
bool isEmpty(); bool isEmpty();
void clearDirty(); void clearDirty();

View file

@ -52,7 +52,7 @@ void Tag::print(ostream out)
out << ""; out << "";
} }
void Tag::print(char *prefix, wostream out) void Tag::print(char *prefix, wostream& out)
{ {
wstring name = getName(); wstring name = getName();

View file

@ -32,7 +32,7 @@ public:
virtual wstring toString() = 0; virtual wstring toString() = 0;
virtual byte getId() = 0; virtual byte getId() = 0;
void print(ostream out); void print(ostream out);
void print(char *prefix, wostream out); void print(char *prefix, wostream& out);
wstring getName(); wstring getName();
Tag *setName(const wstring& name); Tag *setName(const wstring& name);
static Tag *readNamedTag(DataInput *dis); static Tag *readNamedTag(DataInput *dis);

View file

@ -145,6 +145,8 @@ set(_MINECRAFT_WORLD_COMMON_COM_MOJANG_NBT
"${CMAKE_CURRENT_SOURCE_DIR}/Tag.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Tag.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Tag.h" "${CMAKE_CURRENT_SOURCE_DIR}/Tag.h"
"${CMAKE_CURRENT_SOURCE_DIR}/com.mojang.nbt.h" "${CMAKE_CURRENT_SOURCE_DIR}/com.mojang.nbt.h"
"${CMAKE_CURRENT_SOURCE_DIR}/Rotations.h"
"${CMAKE_CURRENT_SOURCE_DIR}/Rotations.cpp"
) )
source_group("com/mojang/nbt" FILES ${_MINECRAFT_WORLD_COMMON_COM_MOJANG_NBT}) source_group("com/mojang/nbt" FILES ${_MINECRAFT_WORLD_COMMON_COM_MOJANG_NBT})