diff --git a/Minecraft.Client/AbstractArmorLayer.cpp b/Minecraft.Client/AbstractArmorLayer.cpp new file mode 100644 index 00000000..64070246 --- /dev/null +++ b/Minecraft.Client/AbstractArmorLayer.cpp @@ -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 +} + diff --git a/Minecraft.Client/AbstractArmorLayer.h b/Minecraft.Client/AbstractArmorLayer.h new file mode 100644 index 00000000..a7709969 --- /dev/null +++ b/Minecraft.Client/AbstractArmorLayer.h @@ -0,0 +1,27 @@ +#pragma once +#include +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(); +}; \ No newline at end of file diff --git a/Minecraft.Client/ArmorStandArmorModel.cpp b/Minecraft.Client/ArmorStandArmorModel.cpp new file mode 100644 index 00000000..9fe22535 --- /dev/null +++ b/Minecraft.Client/ArmorStandArmorModel.cpp @@ -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, + unsigned int uiBitmaskOverrideAnim) +{ + if (!entity) return; + + + if (!entity->instanceof(eTYPE_ARMORSTAND)) return; + + shared_ptr stand = dynamic_pointer_cast(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); +} \ No newline at end of file diff --git a/Minecraft.Client/ArmorStandArmorModel.h b/Minecraft.Client/ArmorStandArmorModel.h new file mode 100644 index 00000000..9fd5c13a --- /dev/null +++ b/Minecraft.Client/ArmorStandArmorModel.h @@ -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, + unsigned int uiBitmaskOverrideAnim = 0) override; +}; \ No newline at end of file diff --git a/Minecraft.Client/ArmorStandModel.cpp b/Minecraft.Client/ArmorStandModel.cpp index 51263a95..c6349eb9 100644 --- a/Minecraft.Client/ArmorStandModel.cpp +++ b/Minecraft.Client/ArmorStandModel.cpp @@ -1,115 +1,138 @@ + #include "stdafx.h" #include "ModelPart.h" #include "ArmorStandModel.h" #include "../Minecraft.World/ArmorStand.h" -ArmorStandModel::ArmorStandModel() : HumanoidModel() +ArmorStandModel::ArmorStandModel(float scale) : HumanoidModel(scale) { texWidth = 64; texHeight = 64; head = new ModelPart(this, 0, 0); - head->addBox(-1.0F, -7.0F, -1.0F, 2, 7, 2, 0.0F); - head->setPos(0.0F, 1.0F, 0.0F); + head->addBox(-1.0f, -7.0f, -1.0f, 2, 7, 2, scale); + head->setPos(0.0f, 0.0f, 0.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->addBox(-6.0F, 0.0F, -1.5F, 12, 3, 3, 0.0F); - body->setPos(0.0F, 0.0F, 0.0F); + body->addBox(-6.0f, 0.0f, -1.5f, 12, 3, 3, scale); + body->setPos(0.0f, 0.0f, 0.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->addBox(0.0F, -2.0F, -1.0F, 2, 12, 2, 0.0F); - arm1->setPos(5.0F, 2.0F, 0.0F); + + arm1 = new ModelPart(this, 24, 0); + arm1->addBox(-2.0f, -2.0f, -1.0f, 2, 12, 2, scale); + arm1->setPos(-5.0f, 2.0f, 0.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); - leg0->setPos(-1.9F, 12.0F, 0.0F); + + arm0 = new ModelPart(this, 32, 16); + 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); - leg1 = new ModelPart(this, 40, 16); // left - leg1->addBox(-1.0F, 0.0F, -1.0F, 2, 11, 2, 0.0F); - leg1->setPos(1.9F, 12.0F, 0.0F); + + leg1 = new ModelPart(this, 40, 16); + 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); - //sticks + rightBodyStick = new ModelPart(this, 16, 0); - rightBodyStick->addBox(-3.0F, 3.0F, -1.0F, 2, 7, 2, 0.0F); - rightBodyStick->setPos(0.0F, 0.0F, 0.0F); + rightBodyStick->addBox(-3.0f, 3.0f, -1.0f, 2, 7, 2, scale); + rightBodyStick->setPos(0.0f, 0.0f, 0.0f); + rightBodyStick->visible = false; rightBodyStick->compile(1.0f / 16.0f); + leftBodyStick = new ModelPart(this, 48, 16); - leftBodyStick->addBox(1.0F, 3.0F, -1.0F, 2, 7, 2, 0.0F); - leftBodyStick->setPos(0.0F, 0.0F, 0.0F); + leftBodyStick->addBox(1.0f, 3.0f, -1.0f, 2, 7, 2, scale); + leftBodyStick->setPos(0.0f, 0.0f, 0.0f); + leftBodyStick->visible = false; leftBodyStick->compile(1.0f / 16.0f); - shoulderStick = new ModelPart(this, 0, 48); - shoulderStick->addBox(-4.0F, 10.0F, -1.0F, 8, 2, 2, 0.0F); - shoulderStick->setPos(0.0F, 0.0F, 0.0F); + + shoulderStick = new ModelPart(this, 0, 48); + shoulderStick->addBox(-4.0f, 10.0f, -1.0f, 8, 2, 2, scale); + shoulderStick->setPos(0.0f, 0.0f, 0.0f); shoulderStick->compile(1.0f / 16.0f); + basePlate = new ModelPart(this, 0, 32); - basePlate->addBox(-6.0F, 11.0F, -6.0F, 12, 1, 12, 0.0F); - basePlate->setPos(0.0F, 12.0F, 0.0F); + basePlate->mirror(); + 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); } -void ArmorStandModel::setupPose(float hX, float hY, float hZ, - float bX, float bY, float bZ, - float lAX, float lAY, float lAZ, - float rAX, float rAY, float rAZ, - float lLX, float lLY, float lLZ, - float rLX, float rLY, float rLZ) +void ArmorStandModel::setupPose( + float hX, float hY, float hZ, + float bX, float bY, float bZ, + float lAX, float lAY, float lAZ, + float rAX, float rAY, float rAZ, + float lLX, float lLY, float lLZ, + float rLX, float rLY, float rLZ) { 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; rightBodyStick->xRot = bX; rightBodyStick->yRot = bY; rightBodyStick->zRot = bZ; leftBodyStick->xRot = bX; leftBodyStick->yRot = bY; leftBodyStick->zRot = bZ; shoulderStick->xRot = bX; shoulderStick->yRot = bY; shoulderStick->zRot = bZ; - arm1->xRot = lAX; arm1->yRot = lAY; arm1->zRot = lAZ; // left - arm0->xRot = rAX; arm0->yRot = rAY; arm0->zRot = rAZ; // right + arm1->xRot = lAX; arm1->yRot = lAY; arm1->zRot = lAZ; + arm0->xRot = rAX; arm0->yRot = rAY; arm0->zRot = rAZ; - leg1->xRot = lLX; leg1->yRot = lLY; leg1->zRot = lLZ; // left - leg0->xRot = rLX; leg0->yRot = rLY; leg0->zRot = rLZ; // right + leg1->xRot = lLX; leg1->yRot = lLY; leg1->zRot = lLZ; + leg0->xRot = rLX; leg0->yRot = rLY; leg0->zRot = rLZ; } -void ArmorStandModel::render(shared_ptr 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, + unsigned int uiBitmaskOverrideAnim) +{ + +} + +void ArmorStandModel::render(shared_ptr entity, + float time, float r, float bob, + float yRot, float xRot, + float scale, bool usecompiled) { shared_ptr stand = dynamic_pointer_cast(entity); - if (stand) { - - bool armsVisible = stand->showArms(); - arm0->visible = armsVisible; // right - arm1->visible = armsVisible; // left + if (stand) + { + bool armsVis = stand->isShowArms(); + bool baseVis = stand->showBasePlate(); + bool isSmallSt = stand->isSmall(); - - // basePlate->visible = stand->showBasePlate(); + arm0->visible = armsVis; + arm1->visible = armsVis; + + rightBodyStick->visible = !isSmallSt; + leftBodyStick->visible = !isSmallSt; + shoulderStick->visible = !isSmallSt; + basePlate->visible = baseVis; } - HumanoidModel::render(entity, time, r, bob, yRot, xRot, scale, usecompiled); - rightBodyStick->render(scale, usecompiled); leftBodyStick->render(scale, usecompiled); shoulderStick->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, unsigned int uiBitmaskOverrideAnim) -{ - + basePlate->render(scale, usecompiled); } \ No newline at end of file diff --git a/Minecraft.Client/ArmorStandModel.h b/Minecraft.Client/ArmorStandModel.h index 85bc2ac6..4a581842 100644 --- a/Minecraft.Client/ArmorStandModel.h +++ b/Minecraft.Client/ArmorStandModel.h @@ -1,23 +1,23 @@ + #pragma once -#include "HumanoidModel.h" +#include "HumanoidModel.h" #include "ModelPart.h" class ArmorStandModel : public HumanoidModel { public: - - ModelPart *rightBodyStick; - ModelPart *leftBodyStick; - ModelPart *shoulderStick; - ModelPart *basePlate; + ModelPart* rightBodyStick; + ModelPart* leftBodyStick; + ModelPart* shoulderStick; + ModelPart* basePlate; - bool showArms; - bool showBasePlate; - bool isSmall; + ArmorStandModel(float scale = 0.0f); + virtual ~ArmorStandModel() {} + + virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, + float scale, shared_ptr entity, + unsigned int uiBitmaskOverrideAnim = 0) override; - ArmorStandModel(); - virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, shared_ptr entity, unsigned int uiBitmaskOverrideAnim ) override; - void setupPose(float hX, float hY, float hZ, float bX, float bY, float bZ, float lAX, float lAY, float lAZ, diff --git a/Minecraft.Client/ArmorStandRenderer.cpp b/Minecraft.Client/ArmorStandRenderer.cpp index d7fb0506..03b53b4d 100644 --- a/Minecraft.Client/ArmorStandRenderer.cpp +++ b/Minecraft.Client/ArmorStandRenderer.cpp @@ -1,61 +1,99 @@ #include "stdafx.h" #include "ArmorStandRenderer.h" -#include "Textures.h" -#include "HumanoidModel.h" #include "ArmorStandModel.h" -#include "..\Minecraft.World\ArmorStand.h" - - - -class ArmorStandArmorModel : public HumanoidModel { -public: - ArmorStandArmorModel(float scale) : HumanoidModel(scale) {} - - - virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, shared_ptr entity, unsigned int uiBitmaskOverrideAnim = 0) override { - - } -}; - +#include "ArmorStandArmorModel.h" +#include "HumanoidModel.h" +#include "ItemInHandLayer.h" +#include "CustomHeadLayer.h" +#include "Textures.h" +#include "HumanoidMobRenderer.h" +#include "../Minecraft.World/ArmorStand.h" +#include "../Minecraft.World/ArmorItem.h" 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); } -ResourceLocation *ArmorStandRenderer::getTextureLocation(shared_ptr entity) + +ArmorStandRenderer::ArmorStandRenderer() + : LivingEntityRenderer(new ArmorStandModel(0.0f), 0.0f) +{ + + addLayer(new ArmorStandArmorLayer(this)); + + + addLayer(new ItemInHandLayer(this)); + + + ArmorStandModel* m = static_cast(getModel()); + addLayer(new CustomHeadLayer(m->head)); +} + +ArmorStandRenderer::~ArmorStandRenderer() +{ + +} + +ResourceLocation* ArmorStandRenderer::getTextureLocation(shared_ptr entity) { return &LOC_ARMOR_STAND; } -void ArmorStandRenderer::createArmorParts() +bool ArmorStandRenderer::shouldShowName(shared_ptr entity) { - armorParts1 = new ArmorStandArmorModel(1.0f); - armorParts2 = new ArmorStandArmorModel(0.5f); + if (!entity) return false; + return entity->isCustomNameVisible(); } -void ArmorStandRenderer::render(shared_ptr entity, double x, double y, double z, float rot, float a) -{ - HumanoidMobRenderer::render(entity, x, y, z, rot, a); -} - -void ArmorStandRenderer::renderModel(shared_ptr mob, float wp, float ws, float bob, - float headRotMinusBodyRot, float headRotx, float scale) +void ArmorStandRenderer::setupRotations(shared_ptr mob, + float bob, float bodyRot, float a) { + glRotatef(180.0f - bodyRot, 0.0f, 1.0f, 0.0f); +} + +void ArmorStandRenderer::render(shared_ptr entity, + double x, double y, double z, + float rot, float a) +{ + LivingEntityRenderer::render(entity, x, y, z, rot, a); +} + +void ArmorStandRenderer::renderModel(shared_ptr mob, + float wp, float ws, float bob, + float headRotMinusBodyRot, + float headRotx, float scale) +{ shared_ptr stand = dynamic_pointer_cast(mob); if (!stand) return; - ArmorStandModel *m = static_cast(model); + ArmorStandModel* m = static_cast(getModel()); if (!m) return; - + Rotations h = stand->getHeadPose(); Rotations b = stand->getBodyPose(); @@ -66,46 +104,118 @@ void ArmorStandRenderer::renderModel(shared_ptr mob, float wp, flo m->setupPose( - h.x * DEG_TO_RAD, h.y * DEG_TO_RAD, h.z * DEG_TO_RAD, - b.x * DEG_TO_RAD, b.y * DEG_TO_RAD, b.z * DEG_TO_RAD, - la.x * DEG_TO_RAD, la.y * DEG_TO_RAD, la.z * DEG_TO_RAD, - ra.x * DEG_TO_RAD, ra.y * DEG_TO_RAD, ra.z * DEG_TO_RAD, - ll.x * DEG_TO_RAD, ll.y * DEG_TO_RAD, ll.z * DEG_TO_RAD, - rl.x * DEG_TO_RAD, rl.y * DEG_TO_RAD, rl.z * DEG_TO_RAD + h.getX() * DEG_TO_RAD, h.getY() * DEG_TO_RAD, h.getZ() * DEG_TO_RAD, + b.getX() * DEG_TO_RAD, b.getY() * DEG_TO_RAD, b.getZ() * DEG_TO_RAD, + la.getX() * DEG_TO_RAD, la.getY() * DEG_TO_RAD, la.getZ() * DEG_TO_RAD, + ra.getX() * DEG_TO_RAD, ra.getY() * DEG_TO_RAD, ra.getZ() * DEG_TO_RAD, + ll.getX() * DEG_TO_RAD, ll.getY() * DEG_TO_RAD, ll.getZ() * DEG_TO_RAD, + rl.getX() * DEG_TO_RAD, rl.getY() * DEG_TO_RAD, rl.getZ() * DEG_TO_RAD ); - - - HumanoidModel *a1 = static_cast(armorParts1); - 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; - 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; } - - 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 - 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 - - 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 - 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 - } - - HumanoidModel *a2 = static_cast(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); + ArmorStandArmorLayer* al = getArmorLayer(); + + if (al) + { + auto applyPose = [&](HumanoidModel* am) + { + if (!am) return; + + + am->head->xRot = h.getX() * DEG_TO_RAD; + am->head->yRot = h.getY() * DEG_TO_RAD; + am->head->zRot = h.getZ() * DEG_TO_RAD; + if (am->hair) { + am->hair->xRot = h.getX() * DEG_TO_RAD; + am->hair->yRot = h.getY() * DEG_TO_RAD; + am->hair->zRot = h.getZ() * DEG_TO_RAD; + } + + + am->body->xRot = b.getX() * DEG_TO_RAD; + am->body->yRot = b.getY() * DEG_TO_RAD; + am->body->zRot = b.getZ() * DEG_TO_RAD; + + + am->arm1->xRot = la.getX() * DEG_TO_RAD; + am->arm1->yRot = la.getY() * DEG_TO_RAD; + am->arm1->zRot = la.getZ() * DEG_TO_RAD; + + + am->arm0->xRot = ra.getX() * DEG_TO_RAD; + am->arm0->yRot = ra.getY() * DEG_TO_RAD; + am->arm0->zRot = ra.getZ() * DEG_TO_RAD; + + + am->leg0->xRot = rl.getX() * DEG_TO_RAD; + am->leg0->yRot = rl.getY() * DEG_TO_RAD; + am->leg0->zRot = rl.getZ() * DEG_TO_RAD; + + + am->leg1->xRot = ll.getX() * DEG_TO_RAD; + am->leg1->yRot = ll.getY() * DEG_TO_RAD; + am->leg1->zRot = ll.getZ() * DEG_TO_RAD; + }; + + applyPose(static_cast(al->armorModel1)); + applyPose(static_cast(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 mob, int layer, float a) +{ + if (!armorLayer) return -1; + shared_ptr itemInstance = mob->getArmor(3 - layer); + if (itemInstance != nullptr) + { + Item *item = itemInstance->getItem(); + ArmorItem *armorItem = dynamic_cast(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((color >> 16) & 0xFF) / 255.0f; + float green = static_cast((color >> 8) & 0xFF) / 255.0f; + float blue = static_cast(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; +} \ No newline at end of file diff --git a/Minecraft.Client/ArmorStandRenderer.h b/Minecraft.Client/ArmorStandRenderer.h index 320b98fa..827c5a66 100644 --- a/Minecraft.Client/ArmorStandRenderer.h +++ b/Minecraft.Client/ArmorStandRenderer.h @@ -1,24 +1,54 @@ #pragma once -#include "HumanoidMobRenderer.h" -#include "ArmorStandModel.h" -#include "..\Minecraft.World\ArmorStand.h" +#include "LivingEntityRenderer.h" +#include "HumanoidArmorLayer.h" +#include "ResourceLocation.h" -class ArmorStandRenderer : public HumanoidMobRenderer -{ -private: - static ResourceLocation LOC_ARMOR_STAND; +#include +class ArmorStandModel; +class LivingEntity; +class Entity; +class RenderLayer; + +class ArmorStandRenderer : public LivingEntityRenderer { public: - ArmorStandRenderer(); - virtual ~ArmorStandRenderer() {} - virtual void render(shared_ptr entity, double x, double y, double z, float rot, float a) override; - virtual ResourceLocation *getTextureLocation(shared_ptr entity) override; + class ArmorStandArmorLayer : public HumanoidArmorLayer { + public: + explicit ArmorStandArmorLayer(LivingEntityRenderer* renderer); + virtual ~ArmorStandArmorLayer() {} + virtual void createArmorModels() override; + }; protected: - - virtual void createArmorParts() override; + std::vector renderLayers; + ArmorStandArmorLayer* armorLayer; - - virtual void renderModel(shared_ptr mob, float wp, float ws, float bob, - float headRotMinusBodyRot, float headRotx, float scale) 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; + + ArmorStandRenderer(); + virtual ~ArmorStandRenderer(); + + virtual ResourceLocation* getTextureLocation(shared_ptr entity) override; + virtual bool shouldShowName(shared_ptr mob) override; + virtual void setupRotations(shared_ptr mob, + float bob, float bodyRot, float a) override; + virtual void render(shared_ptr entity, + double x, double y, double z, + float rot, float a) override; + virtual void renderModel(shared_ptr mob, + float wp, float ws, float bob, + float headRotMinusBodyRot, + float headRotx, float scale) override; + virtual int prepareArmor(shared_ptr mob, int layer, float a) override; }; \ No newline at end of file diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp index 881f9cf5..d13356f9 100644 --- a/Minecraft.Client/ClientConnection.cpp +++ b/Minecraft.Client/ClientConnection.cpp @@ -4300,20 +4300,22 @@ void ClientConnection::handleSetPlayerTeamPacket(shared_ptr void ClientConnection::handleParticleEvent(shared_ptr packet) { - wstring particleName = packet->getName(); - ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)Integer::parseInt(particleName); + const ParticleType* type = packet->getType(); + if (type == nullptr) return; - for (int i = 0; i < packet->getCount(); i++) - { - double xVarience = random->nextGaussian() * packet->getXDist(); - double yVarience = random->nextGaussian() * packet->getYDist(); - double zVarience = random->nextGaussian() * packet->getZDist(); - double xa = random->nextGaussian() * packet->getMaxSpeed(); - double ya = random->nextGaussian() * packet->getMaxSpeed(); - double za = random->nextGaussian() * packet->getMaxSpeed(); + ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)type->getId(); - level->addParticle(particleId, packet->getX() + xVarience, packet->getY() + yVarience, packet->getZ() + zVarience, xa, ya, za); - } + for (int i = 0; i < packet->getCount(); i++) + { + double xVarience = random->nextGaussian() * packet->getXDist(); + double yVarience = random->nextGaussian() * packet->getYDist(); + double zVarience = random->nextGaussian() * packet->getZDist(); + double xa = random->nextGaussian() * packet->getMaxSpeed(); + double ya = random->nextGaussian() * packet->getMaxSpeed(); + double za = random->nextGaussian() * packet->getMaxSpeed(); + + level->addParticle(particleId, packet->getX() + xVarience, packet->getY() + yVarience, packet->getZ() + zVarience, xa, ya, za); + } } void ClientConnection::handleUpdateAttributes(shared_ptr packet) diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp index 0f5c01fc..0ca50199 100644 --- a/Minecraft.Client/Common/Consoles_App.cpp +++ b/Minecraft.Client/Common/Consoles_App.cpp @@ -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, ...) { diff --git a/Minecraft.Client/Common/Consoles_App.h b/Minecraft.Client/Common/Consoles_App.h index 53a7f8e8..fc51e147 100644 --- a/Minecraft.Client/Common/Consoles_App.h +++ b/Minecraft.Client/Common/Consoles_App.h @@ -24,6 +24,8 @@ using namespace std; #include "../ArchiveFile.h" #include "lce_filesystem/FolderFile.h" + + typedef struct _JoinFromInviteData { DWORD dwUserIndex; // dwUserIndex @@ -53,6 +55,7 @@ class Model; class ModelPart; class StringTable; class Merchant; +struct _SkinAdjustments; class CMinecraftAudio; @@ -64,7 +67,7 @@ class CMinecraftApp { private: static int s_iHTMLFontSizesA[eHTMLSize_COUNT]; - + unordered_map m_SkinAdjustmentsMap; public: CMinecraftApp(); @@ -82,6 +85,8 @@ public: // storing credits text from the DLC std::vector 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 // 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 diff --git a/Minecraft.Client/Common/DLC/DLCSkinFile.cpp b/Minecraft.Client/Common/DLC/DLCSkinFile.cpp index d6ba11d5..fb5282af 100644 --- a/Minecraft.Client/Common/DLC/DLCSkinFile.cpp +++ b/Minecraft.Client/Common/DLC/DLCSkinFile.cpp @@ -15,7 +15,11 @@ DLCSkinFile::DLCSkinFile(const wstring &path) : DLCFile(DLCManager::e_DLCType_Sk m_bIsFree = false; m_uiAnimOverrideBitmask=0L; } - +void DLCSkinFile::getSkinAdjustments(_SkinAdjustments* adj) +{ + + memcpy(adj, &m_skinAdjustments, sizeof(_SkinAdjustments)); +} void DLCSkinFile::addData(PBYTE pbData, DWORD dwBytes) { app.AddMemoryTextureFile(m_path,pbData,dwBytes); diff --git a/Minecraft.Client/Common/DLC/DLCSkinFile.h b/Minecraft.Client/Common/DLC/DLCSkinFile.h index 1645fb2a..eb9f70be 100644 --- a/Minecraft.Client/Common/DLC/DLCSkinFile.h +++ b/Minecraft.Client/Common/DLC/DLCSkinFile.h @@ -1,6 +1,7 @@ #pragma once #include "DLCFile.h" #include "../../../Minecraft.Client/HumanoidModel.h" +#include "../../../Minecraft.World/Entity.h" class DLCSkinFile : public DLCFile { @@ -12,11 +13,12 @@ private: unsigned int m_uiAnimOverrideBitmask; bool m_bIsFree; vector m_AdditionalBoxes; + _SkinAdjustments m_skinAdjustments; public: DLCSkinFile(const wstring &path); - + void getSkinAdjustments(_SkinAdjustments* adj); void addData(PBYTE pbData, DWORD dwBytes) override; void addParameter(DLCManager::EDLCParameterType type, const wstring &value) override; diff --git a/Minecraft.Client/Common/res/1_2_2/mob/armor_stand.png b/Minecraft.Client/Common/res/1_2_2/mob/armor_stand.png new file mode 100644 index 00000000..79459cc5 Binary files /dev/null and b/Minecraft.Client/Common/res/1_2_2/mob/armor_stand.png differ diff --git a/Minecraft.Client/Common/res/TitleUpdate/res/mob/armor_stand.png b/Minecraft.Client/Common/res/TitleUpdate/res/mob/armor_stand.png new file mode 100644 index 00000000..79459cc5 Binary files /dev/null and b/Minecraft.Client/Common/res/TitleUpdate/res/mob/armor_stand.png differ diff --git a/Minecraft.Client/CustomHeadLayer.cpp b/Minecraft.Client/CustomHeadLayer.cpp new file mode 100644 index 00000000..a62cfca0 --- /dev/null +++ b/Minecraft.Client/CustomHeadLayer.cpp @@ -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 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 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(); +} \ No newline at end of file diff --git a/Minecraft.Client/CustomHeadLayer.h b/Minecraft.Client/CustomHeadLayer.h new file mode 100644 index 00000000..f4b83301 --- /dev/null +++ b/Minecraft.Client/CustomHeadLayer.h @@ -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 mob, + float wp, float ws, float bob, + float headRot, float headRotX, + float scale, bool useCompiled) override; +}; \ No newline at end of file diff --git a/Minecraft.Client/GameMode.cpp b/Minecraft.Client/GameMode.cpp index 7d791d28..56492bc7 100644 --- a/Minecraft.Client/GameMode.cpp +++ b/Minecraft.Client/GameMode.cpp @@ -180,3 +180,7 @@ void GameMode::handleDebugOptions(unsigned int uiVal, shared_ptr player) { player->SetDebugOptions(uiVal); } +bool GameMode::isSpectator() +{ + return gameType == GameType::SPECTATOR; +} \ No newline at end of file diff --git a/Minecraft.Client/HumanoidArmorLayer.cpp b/Minecraft.Client/HumanoidArmorLayer.cpp new file mode 100644 index 00000000..449a06e3 --- /dev/null +++ b/Minecraft.Client/HumanoidArmorLayer.cpp @@ -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; + } +} \ No newline at end of file diff --git a/Minecraft.Client/HumanoidArmorLayer.h b/Minecraft.Client/HumanoidArmorLayer.h new file mode 100644 index 00000000..ef731be0 --- /dev/null +++ b/Minecraft.Client/HumanoidArmorLayer.h @@ -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); +}; \ No newline at end of file diff --git a/Minecraft.Client/HumanoidModel.cpp b/Minecraft.Client/HumanoidModel.cpp index 8649f6f9..2c83e025 100644 --- a/Minecraft.Client/HumanoidModel.cpp +++ b/Minecraft.Client/HumanoidModel.cpp @@ -967,4 +967,39 @@ void HumanoidModel::render(HumanoidModel *model, float scale, bool usecompiled) pants0->render(scale, usecompiled,(m_uiAnimOverrideBitmask&(1<0); if (pants1) pants1->render(scale, usecompiled,(m_uiAnimOverrideBitmask&(1<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; } \ No newline at end of file diff --git a/Minecraft.Client/HumanoidModel.h b/Minecraft.Client/HumanoidModel.h index afab5cd8..1e589c80 100644 --- a/Minecraft.Client/HumanoidModel.h +++ b/Minecraft.Client/HumanoidModel.h @@ -1,78 +1,93 @@ -#pragma once +#pragma once #include "Model.h" - class HumanoidModel : public Model { public: - ModelPart *head, *hair, *body, *jacket, *arm0, *sleeve0, *arm1, *sleeve1, *leg0, *pants0, *leg1, *pants1, *ear, *cloak; - //ModelPart *hat; - - int holdingLeftHand; + ModelPart *head, *hair, *body, *jacket, *arm0, *sleeve0, *arm1, *sleeve1, *leg0, *pants0, *leg1, *pants1, *ear, *cloak; + int holdingLeftHand; int holdingRightHand; - bool idle; - bool sneaking; - bool bowAndArrow; - bool eating; // 4J added - float eating_t; // 4J added - float eating_swing; // 4J added - unsigned int m_uiAnimOverrideBitmask; // 4J added - float m_fYOffset; // 4J added - enum animbits - { - eAnim_ArmsDown =0, - eAnim_ArmsOutFront, - eAnim_NoLegAnim, - eAnim_HasIdle, - eAnim_ForceAnim, // Claptrap looks bad if the user turns off custom skin anim - // 4J-PB - DaveK wants Fish characters to move both legs in the same way - eAnim_SingleLegs, - eAnim_SingleArms, - eAnim_StatueOfLiberty, // Dr Who Weeping Angel - eAnim_DontRenderArmour, // Dr Who Daleks - eAnim_NoBobbing, // Dr Who Daleks - eAnim_DisableRenderHead, - eAnim_DisableRenderArm0, - eAnim_DisableRenderArm1, - eAnim_DisableRenderTorso, - eAnim_DisableRenderLeg0, - eAnim_DisableRenderLeg1, - eAnim_DisableRenderHair, - eAnim_SmallModel, - eAnim_DisableRenderJacket, - eAnim_DisableRenderSleeve0, - eAnim_DisableRenderSleeve1, - eAnim_DisableRenderPants0, - eAnim_DisableRenderPants1 - }; + bool idle; + bool sneaking; + bool bowAndArrow; + bool eating; + float eating_t; + float eating_swing; + unsigned int m_uiAnimOverrideBitmask; + float m_fYOffset; - static const unsigned int m_staticBitmaskIgnorePlayerCustomAnimSetting= (1< 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, unsigned int uiBitmaskOverrideAnim = 0); + 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, bool mirror); + HumanoidModel(float g, float yOffset, int texWidth, int texHeight, bool slimHands, bool mirror, bool force32); + + virtual void render(shared_ptr 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, + unsigned int uiBitmaskOverrideAnim = 0); + void renderHair(float scale, bool usecompiled); void renderEars(float scale, bool usecompiled); - void renderCloak(float scale, bool usecompiled); - void render(HumanoidModel *model, float scale, bool usecompiled); + void renderCloak(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); +}; \ No newline at end of file diff --git a/Minecraft.Client/ItemInHandLayer.cpp b/Minecraft.Client/ItemInHandLayer.cpp new file mode 100644 index 00000000..5e8c40d9 --- /dev/null +++ b/Minecraft.Client/ItemInHandLayer.cpp @@ -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 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 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(); +} \ No newline at end of file diff --git a/Minecraft.Client/ItemInHandLayer.h b/Minecraft.Client/ItemInHandLayer.h new file mode 100644 index 00000000..21b5c8cb --- /dev/null +++ b/Minecraft.Client/ItemInHandLayer.h @@ -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 mob, + float wp, float ws, float bob, + float headRot, float headRotX, + float scale, bool useCompiled) override; +}; \ No newline at end of file diff --git a/Minecraft.Client/LocalPlayer.cpp b/Minecraft.Client/LocalPlayer.cpp index 3d99e0a8..7f3e3792 100644 --- a/Minecraft.Client/LocalPlayer.cpp +++ b/Minecraft.Client/LocalPlayer.cpp @@ -157,7 +157,7 @@ void LocalPlayer::serverAiStep() // mapPlayerChunk(8); } -bool LocalPlayer::isEffectiveAi() +bool LocalPlayer::isEffectiveAi() const { return true; } diff --git a/Minecraft.Client/LocalPlayer.h b/Minecraft.Client/LocalPlayer.h index f34d3d36..f62c1be9 100644 --- a/Minecraft.Client/LocalPlayer.h +++ b/Minecraft.Client/LocalPlayer.h @@ -95,7 +95,7 @@ public: virtual void serverAiStep(); protected: - bool isEffectiveAi(); + bool isEffectiveAi() const; public: virtual void aiStep(); diff --git a/Minecraft.Client/ModelPart.cpp b/Minecraft.Client/ModelPart.cpp index e423a4ae..07d3bc17 100644 --- a/Minecraft.Client/ModelPart.cpp +++ b/Minecraft.Client/ModelPart.cpp @@ -321,3 +321,14 @@ void ModelPart::mimic(ModelPart *o) yRot = o->yRot; 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; +} \ No newline at end of file diff --git a/Minecraft.Client/ModelPart.h b/Minecraft.Client/ModelPart.h index da78e543..61e26ab9 100644 --- a/Minecraft.Client/ModelPart.h +++ b/Minecraft.Client/ModelPart.h @@ -60,4 +60,5 @@ public: void compile(float scale); int getfU() {return xTexOffs;} int getfV() {return yTexOffs;} + static void copyModelPart(ModelPart* src, ModelPart* dst); }; diff --git a/Minecraft.Client/ParticleType.cpp b/Minecraft.Client/ParticleType.cpp new file mode 100644 index 00000000..30dc0721 --- /dev/null +++ b/Minecraft.Client/ParticleType.cpp @@ -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; +} \ No newline at end of file diff --git a/Minecraft.Client/ParticleType.h b/Minecraft.Client/ParticleType.h new file mode 100644 index 00000000..7b3459f9 --- /dev/null +++ b/Minecraft.Client/ParticleType.h @@ -0,0 +1,23 @@ + +#pragma once +#include + +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(); +}; \ No newline at end of file diff --git a/Minecraft.Client/RenderLayer.h b/Minecraft.Client/RenderLayer.h new file mode 100644 index 00000000..654d8bab --- /dev/null +++ b/Minecraft.Client/RenderLayer.h @@ -0,0 +1,14 @@ +#pragma once +#include +using namespace std; +class LivingEntity; + +class RenderLayer { +public: + virtual ~RenderLayer() {} + virtual int colorsOnDamage() = 0; + virtual void render(shared_ptr mob, + float wp, float ws, float bob, + float headRot, float headRotX, + float scale, bool useCompiled) = 0; +}; \ No newline at end of file diff --git a/Minecraft.Client/ServerLevel.cpp b/Minecraft.Client/ServerLevel.cpp index f2a5c75f..ff905d26 100644 --- a/Minecraft.Client/ServerLevel.cpp +++ b/Minecraft.Client/ServerLevel.cpp @@ -1283,22 +1283,6 @@ PortalForcer *ServerLevel::getPortalForcer() 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 = std::make_shared( name, static_cast(x), static_cast(y), static_cast(z), static_cast(xDist), static_cast(yDist), static_cast(zDist), static_cast(speed), count ); - - for(auto& it : players) - { - shared_ptr player = dynamic_pointer_cast(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) void ServerLevel::queueSendTileUpdate(int x, int y, int z) { @@ -1631,4 +1615,35 @@ void ServerLevel::flagEntitiesToBeRemoved(unsigned int *flags, bool *removedFoun { chunkMap->flagEntitiesToBeRemoved(flags, removedFound); } -} \ No newline at end of file +} +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 data) +{ + auto packet = make_shared( + 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 player = dynamic_pointer_cast(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 data) +{ + this->sendParticles(type, false, x, y, z, count, dx, dy, dz, speed, data); +} + diff --git a/Minecraft.Client/ServerLevel.h b/Minecraft.Client/ServerLevel.h index c4fcedfa..792132a4 100644 --- a/Minecraft.Client/ServerLevel.h +++ b/Minecraft.Client/ServerLevel.h @@ -1,11 +1,14 @@ #pragma once #include "../Minecraft.World/net.minecraft.world.level.h" #include "../Minecraft.World/JavaIntHash.h" +#include "../Minecraft.World/ArrayWithLength.h" +#include "ParticleType.h" class ServerChunkCache; class MinecraftServer; class Node; class EntityTracker; class PlayerChunkMap; +class ArrayWithLength; using namespace std; class ServerLevel : public Level @@ -180,5 +183,6 @@ public: static C4JThread* m_updateThread; 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 data); + virtual void sendParticles(const ParticleType* type, double x, double y, double z, int count, double dx, double dy, double dz, double speed, arrayWithLength data); }; diff --git a/Minecraft.Client/ServerPlayer.cpp b/Minecraft.Client/ServerPlayer.cpp index 00cc04b5..5ff71075 100644 --- a/Minecraft.Client/ServerPlayer.cpp +++ b/Minecraft.Client/ServerPlayer.cpp @@ -2065,3 +2065,11 @@ void ServerPlayer::debug_setPosition(double x, double y, double z, double nYRot, connection->teleport(x, y, z, nYRot, nXRot); } #endif +bool ServerPlayer::isSpectator() +{ + if (gameMode == nullptr) + { + return false; + } + return gameMode->getGameType() == GameType::SPECTATOR; +} \ No newline at end of file diff --git a/Minecraft.Client/ServerPlayer.h b/Minecraft.Client/ServerPlayer.h index 1b2111dd..171f5dc7 100644 --- a/Minecraft.Client/ServerPlayer.h +++ b/Minecraft.Client/ServerPlayer.h @@ -158,6 +158,7 @@ public: 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 + bool isSpectator(); public: // 4J Stu - Added hooks for the game rules diff --git a/Minecraft.Client/ServerPlayerGameMode.cpp b/Minecraft.Client/ServerPlayerGameMode.cpp index 67917f76..35e75705 100644 --- a/Minecraft.Client/ServerPlayerGameMode.cpp +++ b/Minecraft.Client/ServerPlayerGameMode.cpp @@ -454,3 +454,8 @@ void ServerPlayerGameMode::setGameRules(GameRulesInstance *rules) if(m_gameRules != nullptr) delete m_gameRules; m_gameRules = rules; } +GameType* ServerPlayerGameMode::getGameType() +{ + + return gameModeForPlayer; +} diff --git a/Minecraft.Client/ServerPlayerGameMode.h b/Minecraft.Client/ServerPlayerGameMode.h index 509e1676..55f7769c 100644 --- a/Minecraft.Client/ServerPlayerGameMode.h +++ b/Minecraft.Client/ServerPlayerGameMode.h @@ -32,6 +32,7 @@ private: public: void setGameRules(GameRulesInstance *rules); GameRulesInstance *getGameRules() { return m_gameRules; } + GameType* getGameType(); public: ServerPlayerGameMode(Level *level); diff --git a/Minecraft.Client/Textures.cpp b/Minecraft.Client/Textures.cpp index 950e6a5b..627255b6 100644 --- a/Minecraft.Client/Textures.cpp +++ b/Minecraft.Client/Textures.cpp @@ -181,7 +181,7 @@ const wchar_t *Textures::preLoaded[TN_COUNT] = L"item/trapped", L"item/trapped_double", - L"item/armor_stand", + L"mob/armor_stand", //L"item/christmas", diff --git a/Minecraft.Client/cmake/sources/Common.cmake b/Minecraft.Client/cmake/sources/Common.cmake index fff2df91..4c6e18ef 100644 --- a/Minecraft.Client/cmake/sources/Common.cmake +++ b/Minecraft.Client/cmake/sources/Common.cmake @@ -647,6 +647,17 @@ set(_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_MODEL_GEOM "${CMAKE_CURRENT_SOURCE_DIR}/ModelPart.h" "${CMAKE_CURRENT_SOURCE_DIR}/TexOffs.cpp" "${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}) @@ -729,6 +740,8 @@ set(_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_PARTICLE "${CMAKE_CURRENT_SOURCE_DIR}/TerrainParticle.h" "${CMAKE_CURRENT_SOURCE_DIR}/WaterDropParticle.cpp" "${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}) diff --git a/Minecraft.World/ArmorStand.cpp b/Minecraft.World/ArmorStand.cpp index 81925869..999917d4 100644 --- a/Minecraft.World/ArmorStand.cpp +++ b/Minecraft.World/ArmorStand.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "com.mojang.nbt.h" #include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.navigation.h" @@ -11,34 +11,52 @@ #include "SynchedEntityData.h" #include "SharedMonsterAttributes.h" #include "ArmorStand.h" -#include "..\Minecraft.Client\Textures.h" -#include "MobCategory.h" +#include "BlockPos.h" +#include "..\Minecraft.Client\ServerLevel.h" #include "ParticleTypes.h" +#include "Random.h" +#include "AABB.h" -const Rotations ArmorStand::DEFAULT_HEAD_POSE ( 0, 0, 0); -const Rotations ArmorStand::DEFAULT_BODY_POSE ( 0, 0, 0); -const Rotations ArmorStand::DEFAULT_LEFT_ARM_POSE (-10, 0,-10); -const Rotations ArmorStand::DEFAULT_RIGHT_ARM_POSE (-15, 0, 10); -const Rotations ArmorStand::DEFAULT_LEFT_LEG_POSE ( -1, 0, -1); -const Rotations ArmorStand::DEFAULT_RIGHT_LEG_POSE ( 1, 0, 1); +const Rotations ArmorStand::DEFAULT_HEAD_POSE (0.0f, 0.0f, 0.0f); +const Rotations ArmorStand::DEFAULT_BODY_POSE (0.0f, 0.0f, 0.0f); +const Rotations ArmorStand::DEFAULT_LEFT_ARM_POSE (-10.0f, 0.0f, -10.0f); +const Rotations ArmorStand::DEFAULT_RIGHT_ARM_POSE (-15.0f, 0.0f, 10.0f); +const Rotations ArmorStand::DEFAULT_LEFT_LEG_POSE (-1.0f, 0.0f, -1.0f); +const Rotations ArmorStand::DEFAULT_RIGHT_LEG_POSE (1.0f, 0.0f, 1.0f); -ArmorStand::ArmorStand(Level *level) - : Mob(level) +ArmorStand::ArmorStand(Level* level) + : LivingEntity(level) { - lastHit = 0; + ArmorStand::init(); +} + +void ArmorStand::init() +{ + registerAttributes(); + defineSynchedData(); + + lastHit = 0; disabledSlots = 0; invisible = false; + isMarkerFlag = false; - for (int i = 0; i < 5; i++) { + for (int i = 0; i < equipmentCount; i++) equipment[i] = nullptr; - } - - this->defineSynchedData(); - registerAttributes(); - setHealth(getMaxHealth()); - this->setSize(0.5f, 1.975f); + + 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); } + void ArmorStand::registerAttributes() { LivingEntity::registerAttributes(); @@ -50,39 +68,130 @@ void ArmorStand::registerAttributes() void ArmorStand::defineSynchedData() { LivingEntity::defineSynchedData(); - entityData->define(DATA_CLIENT_FLAGS, static_cast(0)); - - entityData->define(DATA_HEAD_POSE_X, DEFAULT_HEAD_POSE.x); - entityData->define(DATA_HEAD_POSE_Y, DEFAULT_HEAD_POSE.y); - entityData->define(DATA_HEAD_POSE_Z, DEFAULT_HEAD_POSE.z); - - entityData->define(DATA_BODY_POSE_X, DEFAULT_BODY_POSE.x); - 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 doesn't inherit from Mob, so we must register + // the custom-name fields that Mob::defineSynchedData() normally provides. + entityData->define(3, static_cast(0)); // DATA_CUSTOM_NAME_VISIBLE + entityData->define(2, wstring(L"")); // DATA_CUSTOM_NAME + entityData->define(DATA_CLIENT_FLAGS, static_cast(0)); + entityData->define(DATA_HEAD_POSE, DEFAULT_HEAD_POSE); + entityData->define(DATA_BODY_POSE, DEFAULT_BODY_POSE); + entityData->define(DATA_LEFT_ARM_POSE, DEFAULT_LEFT_ARM_POSE); + entityData->define(DATA_RIGHT_ARM_POSE, DEFAULT_RIGHT_ARM_POSE); + entityData->define(DATA_LEFT_LEG_POSE, DEFAULT_LEFT_LEG_POSE); + entityData->define(DATA_RIGHT_LEG_POSE, DEFAULT_RIGHT_LEG_POSE); } +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() { float lockedRot = this->yRot; - if (this->isInWater()|| this->isInLava()) { - this->yd -= 0.0392; - } LivingEntity::tick(); this->yRot = lockedRot; this->yRotO = lockedRot; @@ -91,368 +200,472 @@ void ArmorStand::tick() this->yHeadRot = 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; + } } -bool ArmorStand::interact(shared_ptr player) + +void ArmorStand::brokenByAnything() { - if (level->isClientSide) return true; - if (isMarker()) return false; - - float dX = this->x - player->x; - float dZ = this->z - player->z; - float distHoriz = sqrt(dX * dX + dZ * dZ); - float pitchRad = player->xRot * (3.14159265f / 180.0f); - float lookYDiff = -tan(pitchRad) * distHoriz; - float hitY = (player->y + 1.62f + lookYDiff) - this->y; - - - int targetSlot = SLOT_WEAPON; - 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; - } - - shared_ptr playerItem = player->getCarriedItem(); - - - int slotToInteract = (playerItem != nullptr) ? getEquipmentSlotForItem(playerItem) : targetSlot; - - if (isSlotDisabled(slotToInteract)) return false; - - shared_ptr standItem = getItemInSlot(slotToInteract); - - - if (playerItem != nullptr) { - shared_ptr 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); + for (int i = 0; i < equipmentCount; i++) + { + if (equipment[i] && equipment[i]->count > 0) + { + spawnAtLocation(equipment[i], 0.0f); + equipment[i] = nullptr; } - } - - else if (standItem != nullptr) { - player->inventory->setItem(player->inventory->selected, standItem); - setEquippedSlot(slotToInteract, nullptr); } - - return true; } -bool ArmorStand::hurt(DamageSource *source, float damage) + +void ArmorStand::brokenByPlayer(shared_ptr 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(source) != nullptr) { + if (dynamic_cast(source) != nullptr) + { shared_ptr attacker = source->getEntity(); - if (attacker != nullptr && attacker->instanceof(eTYPE_PLAYER)) { - if (dynamic_pointer_cast(attacker)->abilities.instabuild) { - level->broadcastEntityEvent(shared_from_this(), (byte)31); + if (attacker != nullptr && attacker->instanceof(eTYPE_PLAYER)) + { + if (dynamic_pointer_cast(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; + if (isFireDamage) + { + float currentHealth = this->getHealth() - 0.15f; this->setHealth(currentHealth); - - if (currentHealth <= 0) { - //level->broadcastEntityEvent(shared_from_this(), (byte)31); - remove(); + if (currentHealth <= 0.5f) + { + brokenByAnything(); + remove(); return true; } - - - return false; + return false; } - - if (now - lastHit > 5) { + 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); + } + else + { + level->broadcastEntityEvent(shared_from_this(), (byte)31); + spawnAtLocation(Item::armor_stand_Id, 1); + brokenByAnything(); 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() + +void ArmorStand::pushEntities() { - return !removed && !isMarker(); -} + AABB* myBox = getBoundingBox(); + AABB* grown = myBox->grow(0.2, 0.0, 0.2); + auto* entities = level->getEntities(shared_from_this(), grown); + if (!entities) return; - -byte ArmorStand::setBit(byte oldBit, int offset, bool value) -{ - if (value) oldBit = (byte)(oldBit | offset); - 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( - entityData->getFloat(slotX), - entityData->getFloat(slotX + 1), - entityData->getFloat(slotX + 2) - ); -} - -void ArmorStand::writeRotation(int slotX, const Rotations &r) -{ - entityData->set(slotX, r.x); - entityData->set(slotX + 1, r.y); - entityData->set(slotX + 2, r.z); -} - -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) -{ - LivingEntity::readAdditionalSaveData(tag); - - invisible = tag->getBoolean(L"Invisible"); - disabledSlots = tag->getInt(L"DisabledSlots"); - setInvisible(invisible); - setSmall (tag->getBoolean(L"Small")); - setShowArms (tag->getBoolean(L"ShowArms")); - setNoBasePlate(tag->getBoolean(L"NoBasePlate")); - setMarker (tag->getBoolean(L"Marker")); - - if (tag->contains(L"Pose")) + for (auto& e : *entities) { - CompoundTag *pose = tag->getCompound(L"Pose"); - auto loadRot = [&](const wchar_t *key, const Rotations &def) -> Rotations { - if (!pose->contains(key)) return def; - ListTag *list = (ListTag *)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 (!e) continue; - if (tag->contains(L"ArmorStandEquipment")) - { - ListTag *eqList = (ListTag *)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; - } - } - } + + if (!e->instanceof(eTYPE_MINECART)) continue; + + + if (distanceToSqr(e) > 0.2) continue; + + + e->push(shared_from_this()); } } -void ArmorStand::addAdditonalSaveData(CompoundTag *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 * { - ListTag *list = new ListTag(); - 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 *eqList = new ListTag(); - for (int i = 0; i < 5; i++) { - CompoundTag *itemTag = new CompoundTag(); - if (equipment[i] != nullptr) { - equipment[i]->save(itemTag); - } - eqList->add(itemTag); - } - tag->put(L"ArmorStandEquipment", eqList); -} - -shared_ptr ArmorStand::getCarriedItem() -{ - return equipment[SLOT_WEAPON]; -} - -shared_ptr ArmorStand::getCarried(int slot) -{ - if (slot == SLOT_WEAPON) return getCarriedItem(); - else if (slot >= SLOT_BOOTS && slot <= SLOT_HELM) return getArmor(slot - 1); - return nullptr; -} +shared_ptr ArmorStand::getCarriedItem() { return equipment[SLOT_WEAPON]; } +shared_ptr ArmorStand::getCarried(int slot) { return (slot >= 0 && slot < equipmentCount) ? equipment[slot] : nullptr; } shared_ptr ArmorStand::getArmor(int pos) { - if (pos >= 0 && pos < 4) { - return equipment[pos + 1]; - } - return nullptr; + int idx = pos + 1; + return (idx >= 1 && idx < equipmentCount) ? equipment[idx] : nullptr; } - void ArmorStand::setEquippedSlot(int slot, shared_ptr item) { - if (slot >= 0 && slot < 5) { - equipment[slot] = item; - } -} - -ItemInstanceArray ArmorStand::getEquipmentSlots() -{ - return equipment; + if (slot >= 0 && slot < equipmentCount) equipment[slot] = item; } +ItemInstanceArray ArmorStand::getEquipmentSlots() { return ItemInstanceArray(equipment, equipmentCount); } int ArmorStand::getEquipmentSlotForItem(shared_ptr 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; + return Mob::getEquipmentSlotForItem(item); } -bool ArmorStand::isSlotDisabled(int slot) const +bool ArmorStand::setSlot(int inventorySlot, shared_ptr item) { - if (slot == SLOT_WEAPON && !showArms()) return true; - return false; -} - -shared_ptr ArmorStand::getItemInSlot(int slot) -{ - if (slot == SLOT_WEAPON) { - return getCarriedItem(); - } else if (slot >= SLOT_BOOTS && slot <= SLOT_HELM) { - return getArmor(slot - 1); + int localSlot; + if (inventorySlot == 0x63) localSlot = SLOT_WEAPON; + else + { + localSlot = inventorySlot - 0x63; + if (localSlot < 0 || localSlot >= equipmentCount) return false; } - return nullptr; + if (item) + { + int naturalSlot = getEquipmentSlotForItem(item); + if (naturalSlot != localSlot) + { + if (localSlot == SLOT_HELM) + { + auto bi = dynamic_cast(item->getItem()); + if (!bi) return false; + } + else return false; + } + } + setEquippedSlot(localSlot, item); + return true; +} + +void ArmorStand::swapItem(shared_ptr player, int slot) +{ + shared_ptr standItem = equipment[slot]; + shared_ptr 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) +{ + if (level->isClientSide) return true; + if (isMarker()) return false; + if (player->isSpectator()) return true; + + + float dX = this->x - player->x; + float dZ = this->z - player->z; + float distHoriz = sqrtf(dX * dX + dZ * dZ); + float pitchRad = player->xRot * (3.14159265f / 180.0f); + float lookYDiff = -tanf(pitchRad) * distHoriz; + float hitY = (player->y + 1.62f + lookYDiff) - this->y; + + if (isSmall()) hitY *= 2.0f; + + shared_ptr carried = player->getCarriedItem(); + + 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 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, const Vec3& hitVec) +{ + if (isMarker()) return false; + if (level->isClientSide) return true; + if (player->isSpectator()) return true; + + shared_ptr 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; + else if (hitY >= legsMin && hitY < legsMax) + targetSlot = SLOT_LEGGINGS; + if (hitY >= 1.6f && equipment[SLOT_HELM]) + targetSlot = SLOT_HELM; + } + + + if (targetSlot == SLOT_WEAPON && !isShowArms()) return false; + + + if ((disabledSlots & (1 << targetSlot)) != 0) return false; + + swapItem(player, targetSlot); + return true; +} + +int ArmorStand::test_interactAt(shared_ptr player, const Vec3& hitVec) +{ + if (isMarker()) return 0; + if (player->isSpectator()) return 0; + shared_ptr 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; +} + + +void ArmorStand::readPose(CompoundTag* poseTag) +{ + auto loadRot = [&](const wchar_t* key, const Rotations& def, int dataSlot) + { + Rotations r = def; + + ListTag* list = static_cast*>( + static_cast(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); +} + +CompoundTag* ArmorStand::writePose() +{ + CompoundTag* pose = new CompoundTag(); + auto save = [&](const wchar_t* key, const Rotations& cur, const Rotations& def) + { 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; +} + +void ArmorStand::readAdditionalSaveData(CompoundTag* tag) +{ + LivingEntity::readAdditionalSaveData(tag); + + if (tag->contains(L"ArmorStandEquipment", 9)) + { + ListTag* eqList = static_cast*>( + static_cast(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")); + setShowArms (tag->getBoolean(L"ShowArms")); + setNoBasePlate (tag->getBoolean(L"NoBasePlate")); + setNoGravity (tag->getBoolean(L"NoGravity")); + setMarker (tag->getBoolean(L"Marker")); + disabledSlots = tag->getInt(L"DisabledSlots"); + + isMarkerFlag = isMarker(); + noPhysics = (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_NO_GRAVITY) != 0; + + CompoundTag* pose = tag->getCompound(L"Pose"); + if (pose && !pose->isEmpty()) readPose(pose); +} + +void ArmorStand::addAdditonalSaveData(CompoundTag* tag) +{ + LivingEntity::addAdditonalSaveData(tag); + + ListTag* eqList = new ListTag(); + for (int i = 0; i < equipmentCount; i++) + { + CompoundTag* itemTag = new CompoundTag(); + if (equipment[i]) equipment[i]->save(itemTag); + eqList->add(itemTag); + } + tag->put(L"ArmorStandEquipment", eqList); + + if (isInvisible()) tag->putBoolean(L"Invisible", true); + tag->putBoolean(L"Small", isSmall()); + tag->putBoolean(L"ShowArms", isShowArms()); + tag->putBoolean(L"NoBasePlate", isNoBasePlate()); + tag->putInt (L"DisabledSlots",disabledSlots); + if (isMarker()) tag->putBoolean(L"Marker", true); + tag->putBoolean(L"NoGravity", noPhysics); + tag->put(L"Pose", writePose()); } void ArmorStand::handleEntityEvent(byte id) { - if (id == 31) + if (id == 31) { - int woodId = (Tile::wood != nullptr) ? Tile::wood->id : 5; - ePARTICLE_TYPE woodParticle = PARTICLE_TILECRACK(woodId, 0); - - for (int i = 0; i < 10; i++) - { - - double xa = random->nextGaussian() * 0.01; - double ya = -0.05; - double za = random->nextGaussian() * 0.01; - - - double px = x + (random->nextFloat() * 0.1f - 0.05f); - - - double py = y + (bbHeight * 0.6f) + (random->nextFloat() * 0.2f); - - double pz = z + (random->nextFloat() * 0.1f - 0.05f); - - level->addParticle(woodParticle, px, py, pz, xa, ya, za); + int woodId = Tile::wood ? Tile::wood->id : 5; + ePARTICLE_TYPE p = PARTICLE_TILECRACK(woodId, 0); + for (int i = 0; i < 10; i++) + { + double xa = random->nextGaussian() * 0.01; + double ya = -0.05; + double za = random->nextGaussian() * 0.01; + double px = x + (random->nextFloat() * 0.1f - 0.05f); + double py = y + (bbHeight * 0.6f) + (random->nextFloat() * 0.2f); + double pz = z + (random->nextFloat() * 0.1f - 0.05f); + level->addParticle(p, px, py, pz, xa, ya, za); + } } - - - - } - else if (id == 32) - lastHit = (long long)tickCount; - else - LivingEntity::handleEntityEvent(id); -} - -bool ArmorStand::updateInWaterState() -{ - - return Entity::updateInWaterState(); -} - + else if (id == 32) lastHit = (long long)tickCount; + else LivingEntity::handleEntityEvent(id); +} \ No newline at end of file diff --git a/Minecraft.World/ArmorStand.h b/Minecraft.World/ArmorStand.h index e8f91311..efbf79ca 100644 --- a/Minecraft.World/ArmorStand.h +++ b/Minecraft.World/ArmorStand.h @@ -1,19 +1,15 @@ #pragma once #include "Mob.h" +#include "Rotations.h" #include "SynchedEntityData.h" +#include "Vec3.h" +#include "Random.h" -struct Rotations -{ - 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 +class ArmorStand : public LivingEntity { public: - eINSTANCEOF GetType() { return eTYPE_ARMORSTAND; } - static Entity *create(Level *level) { return new ArmorStand(level); } + eINSTANCEOF GetType() override { return eTYPE_ARMORSTAND; } + static Entity* create(Level* level) { return new ArmorStand(level); } static const Rotations DEFAULT_HEAD_POSE; static const Rotations DEFAULT_BODY_POSE; @@ -23,50 +19,63 @@ public: static const Rotations DEFAULT_RIGHT_LEG_POSE; private: - static const int DATA_CLIENT_FLAGS = 10; - static const int DATA_HEAD_POSE_X = 11; - static const int DATA_HEAD_POSE_Y = 12; - static const int DATA_HEAD_POSE_Z = 13; - static const int DATA_BODY_POSE_X = 14; - static const int DATA_BODY_POSE_Y = 15; - static const int DATA_BODY_POSE_Z = 16; - 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 DATA_CLIENT_FLAGS = 0xA; + static const int DATA_HEAD_POSE = 0xB; + static const int DATA_BODY_POSE = 0xC; + static const int DATA_LEFT_ARM_POSE = 0xD; + static const int DATA_RIGHT_ARM_POSE = 0xE; + static const int DATA_LEFT_LEG_POSE = 0xF; + static const int DATA_RIGHT_LEG_POSE = 0x10; - static const int FLAG_SMALL = 1; - static const int FLAG_SHOW_ARMS = 4; - static const int FLAG_NO_BASEPLATE = 8; - static const int FLAG_MARKER = 16; + static const int FLAG_SMALL = 1; + static const int FLAG_NO_GRAVITY = 2; + static const int FLAG_SHOW_ARMS = 4; + static const int FLAG_NO_BASEPLATE= 8; + static const int FLAG_MARKER = 16; + +public: + 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: + shared_ptr equipment[equipmentCount]; + + Rotations headPose; + Rotations bodyPose; + Rotations leftArmPose; + Rotations rightArmPose; + Rotations leftLegPose; + Rotations rightLegPose; + + int disabledSlots; + bool invisible; + bool isMarkerFlag; + bool noPhysics; public: long long lastHit; -private: - int disabledSlots; - bool invisible; - -public: - ArmorStand(Level *level); - virtual ~ArmorStand() {} + explicit ArmorStand(Level* level); + virtual ~ArmorStand(); + bool isBaby() const; bool isSmall() const; - bool showArms() const; + bool isShowArms() const; + bool isNoBasePlate() const; bool showBasePlate() const; bool isMarker() const; - void setSmall(bool v); - void setShowArms(bool v); - void setNoBasePlate(bool v); - void setMarker(bool v); + bool isEffectiveAi() const; + + void setSmall (bool v); + void setShowArms (bool v); + void setNoBasePlate (bool v); + void setMarker (bool v); + void setNoGravity (bool v); + void setInvisible (bool v); Rotations getHeadPose() const; Rotations getBodyPose() const; @@ -75,59 +84,82 @@ public: Rotations getLeftLegPose() const; Rotations getRightLegPose() const; - void setHeadPose (const Rotations &r); - void setBodyPose (const Rotations &r); - void setLeftArmPose (const Rotations &r); - void setRightArmPose(const Rotations &r); - void setLeftLegPose (const Rotations &r); - void setRightLegPose(const Rotations &r); + void setHeadPose (const Rotations& r); + void setBodyPose (const Rotations& r); + void setLeftArmPose (const Rotations& r); + void setRightArmPose(const Rotations& r); + void setLeftLegPose (const Rotations& r); + void setRightLegPose(const Rotations& r); - virtual bool useNewAi() override { return false; } - virtual void tick() override; - virtual bool hurt(DamageSource *source, float damage) override; - virtual bool interact(shared_ptr player) override; + + virtual bool useNewAi() override { return false; } + virtual void tick() override; + virtual bool hurt(DamageSource* source, float damage) override; + virtual bool isPickable() override; + virtual bool isPushable() override; + + + bool ignoreExplosion(); + void kill(); + + virtual bool isAttackable() override { return true; } + + virtual bool shouldShowName() override { return false; } + virtual bool isInWall() override { return false; } + + + + virtual float getEyeHeight() override; + + virtual bool shouldRenderAtSqrDistance(double distSq) override; - virtual bool isPickable() override; - virtual bool isPushable() override { return false; } virtual void push(shared_ptr entity) override {} virtual void push(double xa, double ya, double za) override {} - virtual bool isAttackable() override { return true; } - virtual bool isBaby() override { return isSmall(); } - virtual bool shouldShowName() override { return false; } - virtual wstring getAName() override { return L""; } + virtual void pushEntities() override; + + + virtual void doPush(shared_ptr e) override {} + + virtual int getHurtSound() override { return -1; } + virtual int getDeathSound() override { return -1; } + virtual float getSoundVolume() override { return 0.0f; } + virtual bool makeStepSound() 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 interact(shared_ptr player) override; + virtual bool interactAt(shared_ptr player, const Vec3& hitVec); + virtual int test_interactAt(shared_ptr player, const Vec3& hitVec); - virtual shared_ptr getCarriedItem() override; - virtual shared_ptr getCarried(int slot) override; - virtual shared_ptr getArmor(int pos) override; - virtual void setEquippedSlot(int slot, shared_ptr item) override; - virtual ItemInstanceArray getEquipmentSlots() override; + void brokenByAnything(); + void brokenByPlayer(shared_ptr player, DamageSource* source); + void causeDamage(float damage); + + void updateBoundingBox(bool markerMode); + void updateInvisibilityStatus(); + + virtual shared_ptr getCarriedItem() override; + virtual shared_ptr getCarried(int slot) override; + virtual shared_ptr getArmor(int pos) override; + virtual void setEquippedSlot(int slot, shared_ptr item) override; + virtual ItemInstanceArray getEquipmentSlots() override; + bool setSlot(int inventorySlot, shared_ptr item); + void swapItem(shared_ptr player, int slot); + int getEquipmentSlotForItem(shared_ptr item) const; + + virtual void readAdditionalSaveData(CompoundTag* tag) override; + virtual void addAdditonalSaveData (CompoundTag* tag) override; + void readPose(CompoundTag* poseTag); + CompoundTag* writePose(); - virtual void readAdditionalSaveData(CompoundTag *tag) override; - virtual void addAdditonalSaveData(CompoundTag *tag) override; virtual void handleEntityEvent(byte eventId) override; - - virtual bool updateInWaterState() override; protected: virtual void defineSynchedData() override; - virtual void registerAttributes() override; - - virtual int getHurtSound() override { return -1; } - virtual int getDeathSound() override { return -1; } - virtual float getSoundVolume() override { return 0.0f; } - virtual bool makeStepSound() override { return false; } + virtual void registerAttributes() override; private: - byte setBit(byte oldBit, int offset, bool value); - Rotations readRotation(int slotX) const; - void writeRotation(int slotX, const Rotations &r); - - int getEquipmentSlotForItem(shared_ptr item) const; - bool isSlotDisabled(int slot) const; - shared_ptr getItemInSlot(int slot); + void init(); }; \ No newline at end of file diff --git a/Minecraft.World/ArmorStandItem.cpp b/Minecraft.World/ArmorStandItem.cpp index 3f18d703..2df229c2 100644 --- a/Minecraft.World/ArmorStandItem.cpp +++ b/Minecraft.World/ArmorStandItem.cpp @@ -7,6 +7,27 @@ #include "Mth.h" #include "ArmorStandItem.h" #include "..\Minecraft.World\ArmorStand.h" +#include "..\Minecraft.World\Entity.h" + + +ArmorStandItem::ArmorStandItem(int id) : Item(id) +{ + maxStackSize = 16; +} + + +void ArmorStandItem::randomizePose(shared_ptr 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, shared_ptr player, Level *level, int x, int y, int z, int face, @@ -18,20 +39,15 @@ bool ArmorStandItem::useOn(shared_ptr itemInstance, shared_ptrgetTile(px, py, pz) != 0) return false; if (level->getTile(px, py + 1, pz) != 0) return false; - if (bTestUseOnOnly) return true; if (level->isClientSide) return true; @@ -39,7 +55,7 @@ bool ArmorStandItem::useOn(shared_ptr itemInstance, shared_ptryRot + 180.0f; float snapped = (float)(Mth::floor((targetRot + 22.5f) / 45.0f) * 45.0f); - shared_ptr stand = std::make_shared(level); + auto stand = std::make_shared(level); stand->moveTo(px + 0.5, py, pz + 0.5, snapped, 0.0f); stand->yRot = snapped; stand->yBodyRot = snapped; @@ -47,7 +63,6 @@ bool ArmorStandItem::useOn(shared_ptr itemInstance, shared_ptryRotO = snapped; stand->yBodyRotO = snapped; stand->yHeadRotO = snapped; - level->addEntity(stand); if (!player->abilities.instabuild) diff --git a/Minecraft.World/ArmorStandItem.h b/Minecraft.World/ArmorStandItem.h index ffe5312d..e313ac34 100644 --- a/Minecraft.World/ArmorStandItem.h +++ b/Minecraft.World/ArmorStandItem.h @@ -1,14 +1,19 @@ #pragma once #include "Item.h" +#include "ArmorStand.h" class ArmorStandItem : public Item { public: - ArmorStandItem(int id) : Item(id) { maxStackSize = 16; } + explicit ArmorStandItem(int id); virtual ~ArmorStandItem() {} - virtual bool useOn(shared_ptr itemInstance, shared_ptr player, + virtual bool useOn(shared_ptr itemInstance, + shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly = false) override; + + + static void randomizePose(shared_ptr stand, Random *rng); }; \ No newline at end of file diff --git a/Minecraft.World/CompoundTag.h b/Minecraft.World/CompoundTag.h index 8f4d045d..5ea9bca5 100644 --- a/Minecraft.World/CompoundTag.h +++ b/Minecraft.World/CompoundTag.h @@ -10,6 +10,7 @@ #include "StringTag.h" #include "ByteArrayTag.h" #include "IntArrayTag.h" +#include "CompoundContainer.h" class CompoundTag : public Tag { @@ -143,7 +144,29 @@ public: { 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) { if (tags.find(name) == tags.end()) return (byte)0; @@ -198,10 +221,13 @@ public: return static_cast(tags[name])->data; } - CompoundTag *getCompound(const wstring &name) + CompoundTag* getCompound(const wstring& name) { - if (tags.find(name) == tags.end()) return new CompoundTag(name); - return static_cast(tags[name]); + if (contains(name, Tag::TAG_Compound)) + { + return static_cast(get(name)); + } + return new CompoundTag(name); } ListTag *getList(const wstring &name) @@ -297,4 +323,8 @@ public: } return false; } + }; + + + diff --git a/Minecraft.World/DamageSource.cpp b/Minecraft.World/DamageSource.cpp index f567385d..838c77ab 100644 --- a/Minecraft.World/DamageSource.cpp +++ b/Minecraft.World/DamageSource.cpp @@ -111,6 +111,9 @@ bool DamageSource::isBypassInvul() return _bypassInvul; } +bool DamageSource::isBypassMagic() { + return _bypassInvul; +} //DamageSource::DamageSource(const wstring &msgId) DamageSource::DamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId) @@ -214,6 +217,33 @@ bool DamageSource::isFire() { return isFireSource; } +bool DamageSource::isFireProjectile() { + return _isProjectile; +} +DamageSource* DamageSource::setIsFireProjectile() { + _isProjectile = true; + return this; +} +bool DamageSource::isCreativePlayer() const +{ + + shared_ptr entity = const_cast(this)->getEntity(); + + if (entity != nullptr) + { + + shared_ptr player = dynamic_pointer_cast(entity); + + if (player != nullptr) + { + + return player->abilities.instabuild; + } + } + + return false; +} + ChatPacket::EChatPacketMessage DamageSource::getMsgId() { diff --git a/Minecraft.World/DamageSource.h b/Minecraft.World/DamageSource.h index 6d0d5326..f5f2a397 100644 --- a/Minecraft.World/DamageSource.h +++ b/Minecraft.World/DamageSource.h @@ -1,4 +1,6 @@ #pragma once +#include +#include "ChatPacket.h" using namespace std; class LivingEntity; @@ -8,93 +10,105 @@ class Fireball; class Player; class Explosion; -#include "ChatPacket.h" - class DamageSource { public: - static DamageSource *inFire; - static DamageSource *onFire; - static DamageSource *lava; - static DamageSource *inWall; - static DamageSource *drown; - static DamageSource *starve; - static DamageSource *cactus; - static DamageSource *fall; - static DamageSource *outOfWorld; - static DamageSource *genericSource; - static DamageSource *magic; - static DamageSource *dragonbreath; - static DamageSource *wither; - static DamageSource *anvil; - static DamageSource *fallingBlock; + + static DamageSource *inFire; + static DamageSource *onFire; + static DamageSource *lava; + static DamageSource *inWall; + static DamageSource *drown; + static DamageSource *starve; + static DamageSource *cactus; + static DamageSource *fall; + static DamageSource *outOfWorld; + static DamageSource *genericSource; + static DamageSource *magic; + static DamageSource *dragonbreath; + static DamageSource *wither; + static DamageSource *anvil; + static DamageSource *fallingBlock; + + static DamageSource *mobAttack(shared_ptr mob); + static DamageSource *playerAttack(shared_ptr player); + static DamageSource *arrow(shared_ptr arrow, shared_ptr owner); + static DamageSource *fireball(shared_ptr fireball, shared_ptr owner); + static DamageSource *thrown(shared_ptr entity, shared_ptr owner); + static DamageSource *indirectMagic(shared_ptr entity, shared_ptr owner); + static DamageSource *thorns(shared_ptr source); + static DamageSource *explosion(Explosion *explosion); - static DamageSource *mobAttack(shared_ptr mob); - static DamageSource *playerAttack(shared_ptr player); - static DamageSource *arrow(shared_ptr arrow, shared_ptr owner); - static DamageSource *fireball(shared_ptr fireball, shared_ptr owner); - static DamageSource *thrown(shared_ptr entity, shared_ptr owner); - static DamageSource *indirectMagic(shared_ptr entity, shared_ptr owner); - static DamageSource *thorns(shared_ptr source); - static DamageSource *explosion(Explosion *explosion); private: - bool _bypassArmor; - bool _bypassInvul; - // food exhastion caused by being damaged by this source - float exhaustion; - bool isFireSource; - bool _isProjectile; - bool _scalesWithDifficulty; - bool _isMagic; - bool _isExplosion; - bool _isCritical; + + bool _bypassArmor; + + bool _bypassInvul; + + float exhaustion; + + bool isFireSource; + + bool _isProjectile; + + bool _scalesWithDifficulty; + + bool _isMagic; + + bool _isExplosion; + + bool _isCritical; + + public: + ChatPacket::EChatPacketMessage m_msgId; -public: - bool isCritical(); - DamageSource *setIsCritical(); - bool isProjectile(); - DamageSource *setProjectile(); - bool isExplosion(); - DamageSource *setExplosion(); - - bool isBypassArmor(); - 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) + ChatPacket::EChatPacketMessage m_msgWithItemId; protected: - //DamageSource(const wstring &msgId); - DamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId = ChatPacket::e_ChatCustom); + DamageSource(ChatPacket::EChatPacketMessage msgId, + ChatPacket::EChatPacketMessage msgWithItemId = ChatPacket::e_ChatCustom); public: - virtual ~DamageSource() {} + virtual ~DamageSource() {} - virtual shared_ptr getDirectEntity(); - virtual shared_ptr getEntity(); + + virtual shared_ptr getDirectEntity(); + virtual shared_ptr getEntity(); + virtual bool scalesWithDifficulty(); + virtual shared_ptr getDeathMessagePacket(shared_ptr player); + virtual DamageSource *copy(); + + + bool isBypassArmor(); + bool isBypassInvul(); + bool isBypassMagic(); + + bool isFire(); + DamageSource *setIsFire(); + + bool isFireProjectile(); + DamageSource *setIsFireProjectile(); + + bool isProjectile(); + DamageSource *setProjectile(); + + bool isMagic(); + DamageSource *setMagic(); + + bool isExplosion(); + DamageSource *setExplosion(); + + bool isCritical(); + DamageSource *setIsCritical(); + + bool isCreativePlayer() const; + + float getFoodExhaustion(); + ChatPacket::EChatPacketMessage getMsgId(); + bool equals(DamageSource *source); protected: - DamageSource *bypassArmor(); - DamageSource *bypassInvul(); - DamageSource *setIsFire(); - DamageSource *setScalesWithDifficulty(); - -public: - virtual bool scalesWithDifficulty(); - - bool isMagic(); - DamageSource *setMagic(); - - // 4J Stu - Made return a packet - //virtual wstring getLocalizedDeathMessage(shared_ptr player); - virtual shared_ptr getDeathMessagePacket(shared_ptr player); - - bool isFire(); - ChatPacket::EChatPacketMessage getMsgId(); // 4J Stu - Used to return String - - // 4J Added - bool equals(DamageSource *source); - virtual DamageSource *copy(); + DamageSource *bypassArmor(); + DamageSource *bypassInvul(); + DamageSource *setScalesWithDifficulty(); }; \ No newline at end of file diff --git a/Minecraft.World/Entity.cpp b/Minecraft.World/Entity.cpp index e502a7d5..6e3ef44c 100644 --- a/Minecraft.World/Entity.cpp +++ b/Minecraft.World/Entity.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "com.mojang.nbt.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.item.enchantment.h" @@ -2150,4 +2150,225 @@ unsigned int Entity::getAnimOverrideBitmask() } 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(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::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; } \ No newline at end of file diff --git a/Minecraft.World/Entity.h b/Minecraft.World/Entity.h index 9fb0f548..4fe0fb44 100644 --- a/Minecraft.World/Entity.h +++ b/Minecraft.World/Entity.h @@ -18,6 +18,7 @@ class Level; class CompoundTag; class DamageSource; class Explosion; +class BlockPos; // 4J Stu Added this mainly to allow is to record telemetry for player deaths enum EEntityDamageType @@ -31,6 +32,10 @@ enum EEntityDamageType eEntityDamageType_OutOfWorld, eEntityDamageType_Cactus, }; +struct _SkinAdjustments +{ + int data[18]; +}; class Entity : public enable_shared_from_this { @@ -48,6 +53,7 @@ public: private: static int entityCounter; + bool m_outsideWorldBorder = false; public: int entityId; @@ -73,6 +79,7 @@ public: protected: bool isStuckInWeb; + _SkinAdjustments m_skinAdjustments; public: bool slide; @@ -199,7 +206,7 @@ protected: public: virtual void remove(); -protected: +public: virtual void setSize(float w, float h); void setPos(EntityPos *pos); void setRot(float yRot, float xRot); @@ -256,6 +263,7 @@ public: virtual bool updateInWaterState(); bool isUnderLiquid(Material *material); virtual float getHeadHeight(); + float getEyeHeight(); bool isInLava(); void moveRelative(float xa, float za, float speed); virtual int getLightColor(float a); // 4J - change brought forward from 1.8.2 @@ -434,4 +442,77 @@ public: virtual void setDespawnProtected() {} virtual bool couldWander() { return false; } 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, const Vec3& hitVec) { return false; } +virtual void handleEntityTag() {} +virtual int getEntityTag() { return 0; } +virtual int setSlot() { return 0; } + + +Vec3* getCommandSenderWorldPosition(); +Level* getCommandSenderWorld(); +shared_ptr getCommandSenderEntity(); + + +double distanceSqrToBlockPosCenter(int bx, int by, int bz); +double distanceSqrToBlockPosCenter(BlockPos* pos); + + + void getSkinAdjustments(struct _SkinAdjustments* adj); + void setSkinAdjustments(struct _SkinAdjustments* adj); + + }; diff --git a/Minecraft.World/LevelParticlesPacket.cpp b/Minecraft.World/LevelParticlesPacket.cpp index 4d53cf4f..b9d5a840 100644 --- a/Minecraft.World/LevelParticlesPacket.cpp +++ b/Minecraft.World/LevelParticlesPacket.cpp @@ -1,110 +1,127 @@ + #include "stdafx.h" #include "PacketListener.h" #include "LevelParticlesPacket.h" +#include "../Minecraft.Client/ParticleType.h" LevelParticlesPacket::LevelParticlesPacket() { - this->name = L""; - this->x = 0.0f; - this->y = 0.0f; - this->z = 0.0f; - this->xDist = 0.0f; - this->yDist = 0.0f; - this->zDist = 0.0f; - this->maxSpeed = 0.0f; - this->count = 0; + + this->overrideLimiter = false; + this->type = nullptr; + this->count = 0; + this->y = 0.0f; + this->paramCount = 0; + this->x = 0.0f; + this->yDist = 0.0f; + this->zDist = 0.0f; + this->z = 0.0f; + this->maxSpeed = 0.0f; + 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 data) { - this->name = name; - this->x = x; - this->y = y; - this->z = z; - this->xDist = xDist; - this->yDist = yDist; - this->zDist = zDist; - this->maxSpeed = maxSpeed; - this->count = count; + this->type = type; + this->overrideLimiter = overrideLimiter; + this->x = x; + this->y = y; + this->z = z; + this->xDist = xDist; + this->yDist = yDist; + this->zDist = zDist; + this->maxSpeed = maxSpeed; + 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; + } } -void LevelParticlesPacket::read(DataInputStream *dis) +LevelParticlesPacket::~LevelParticlesPacket() { - name = readUtf(dis, 64); - x = dis->readFloat(); - y = dis->readFloat(); - z = dis->readFloat(); - xDist = dis->readFloat(); - yDist = dis->readFloat(); - zDist = dis->readFloat(); - maxSpeed = dis->readFloat(); - count = dis->readInt(); + + if (params) + { + delete[] params; + params = nullptr; + } } -void LevelParticlesPacket::write(DataOutputStream *dos) +void LevelParticlesPacket::read(DataInputStream* dis) { - writeUtf(name, dos); - dos->writeFloat(x); - dos->writeFloat(y); - dos->writeFloat(z); - dos->writeFloat(xDist); - dos->writeFloat(yDist); - dos->writeFloat(zDist); - dos->writeFloat(maxSpeed); - dos->writeInt(count); + int particleId = dis->readInt(); + const ParticleType* resolved = ParticleType::byId(particleId); + if (!resolved) + resolved = ParticleType::getDefault(); + this->type = resolved; + + this->overrideLimiter = dis->readBoolean(); + + 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; + } } -wstring LevelParticlesPacket::getName() +void LevelParticlesPacket::write(DataOutputStream* dos) { - return name; + dos->writeInt(this->type ? this->type->getId() : 0); + dos->writeBoolean(this->overrideLimiter); + dos->writeFloat(this->x); + dos->writeFloat(this->y); + dos->writeFloat(this->z); + dos->writeFloat(this->xDist); + dos->writeFloat(this->yDist); + dos->writeFloat(this->zDist); + dos->writeFloat(this->maxSpeed); + dos->writeInt(this->count); + + int toWrite = this->type ? this->type->getParamCount() : 0; + for (int i = 0; i < toWrite; i++) + { + dos->writeInt(this->params[i]); + } } -double LevelParticlesPacket::getX() +void LevelParticlesPacket::handle(PacketListener* listener) { - 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) -{ - listener->handleParticleEvent(shared_from_this()); + listener->handleParticleEvent(shared_from_this()); } int LevelParticlesPacket::getEstimatedSize() { - return 4 * 2 + 7 * 8; + return 0x40; } \ No newline at end of file diff --git a/Minecraft.World/LevelParticlesPacket.h b/Minecraft.World/LevelParticlesPacket.h index c7870a8e..bd156ec5 100644 --- a/Minecraft.World/LevelParticlesPacket.h +++ b/Minecraft.World/LevelParticlesPacket.h @@ -1,39 +1,53 @@ -#pragma once +#pragma once #include "Packet.h" +#include "../Minecraft.Client/ParticleType.h" class LevelParticlesPacket : public Packet, public enable_shared_from_this { private: - wstring name; - float x; - float y; - float z; - float xDist; - float yDist; - float zDist; - float maxSpeed; - int count; + + const ParticleType* type; + float x; + float y; + float z; + float xDist; + float yDist; + float zDist; + float maxSpeed; + int count; + bool overrideLimiter; + int* params; + int paramCount; public: - 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 data); + ~LevelParticlesPacket(); - void read(DataInputStream *dis); - void write(DataOutputStream *dos); - wstring getName(); - double getX(); - double getY(); - double getZ(); - float getXDist(); - float getYDist(); - float getZDist(); - float getMaxSpeed(); - int getCount(); - void handle(PacketListener *listener); - int getEstimatedSize(); + void read(DataInputStream* dis) override; + void write(DataOutputStream* dos) override; -public: - static shared_ptr create() { return std::make_shared(); } - virtual int getId() { return 63; } + const ParticleType* getType() { return type; } + double getX() { return x; } + double getY() { return y; } + double getZ() { return z; } + double getXDist() { return xDist; } + double getYDist() { return yDist; } + double getZDist() { return zDist; } + double getMaxSpeed() { return maxSpeed; } + int getCount() { return count; } + bool isOverrideLimiter() { return overrideLimiter; } + int* getParams() { return params; } + int getParamCount() { return paramCount; } + + void handle(PacketListener* listener) override; + int getEstimatedSize() override; + + static shared_ptr create() { return std::make_shared(); } + virtual int getId() override { return 63; } }; \ No newline at end of file diff --git a/Minecraft.World/LevelSettings.cpp b/Minecraft.World/LevelSettings.cpp index 4f0536df..bf9b6a56 100644 --- a/Minecraft.World/LevelSettings.cpp +++ b/Minecraft.World/LevelSettings.cpp @@ -7,6 +7,7 @@ GameType *GameType::NOT_SET = nullptr; GameType *GameType::SURVIVAL= nullptr; GameType *GameType::CREATIVE = nullptr; GameType *GameType::ADVENTURE = nullptr; +GameType* GameType::SPECTATOR = nullptr; void GameType::staticCtor() { @@ -14,6 +15,7 @@ void GameType::staticCtor() SURVIVAL = new GameType(0, L"survival"); CREATIVE = new GameType(1, L"creative"); ADVENTURE = new GameType(2, L"adventure"); + SPECTATOR = new GameType(3, L"spectator"); } GameType::GameType(int id, const wstring &name) @@ -59,6 +61,10 @@ bool GameType::isCreative() { return this == CREATIVE; } +bool GameType::isSpectator() +{ + return this == SPECTATOR; +} bool GameType::isSurvival() { diff --git a/Minecraft.World/LevelSettings.h b/Minecraft.World/LevelSettings.h index 73f588f6..a77f0d7a 100644 --- a/Minecraft.World/LevelSettings.h +++ b/Minecraft.World/LevelSettings.h @@ -14,6 +14,7 @@ public: static GameType *SURVIVAL; static GameType *CREATIVE; static GameType *ADVENTURE; + static GameType *SPECTATOR; static void staticCtor(); @@ -30,6 +31,7 @@ public: bool isAdventureRestricted(); bool isCreative(); bool isSurvival(); + bool isSpectator(); static GameType *byId(int id); static GameType *byName(const wstring &name); }; diff --git a/Minecraft.World/ListTag.h b/Minecraft.World/ListTag.h index f79a28fb..dd9698c5 100644 --- a/Minecraft.World/ListTag.h +++ b/Minecraft.World/ListTag.h @@ -45,6 +45,7 @@ public: list.push_back(tag); } } + byte getId() { return TAG_List; } @@ -148,4 +149,7 @@ public: } return false; } + + + }; \ No newline at end of file diff --git a/Minecraft.World/LivingEntity.cpp b/Minecraft.World/LivingEntity.cpp index bc00f2cc..952f0252 100644 --- a/Minecraft.World/LivingEntity.cpp +++ b/Minecraft.World/LivingEntity.cpp @@ -2051,7 +2051,7 @@ HitResult *LivingEntity::pick(double range, float a) return level->clip(from, to); } -bool LivingEntity::isEffectiveAi() +bool LivingEntity::isEffectiveAi()const { return !level->isClientSide; } @@ -2145,4 +2145,4 @@ HitResult *LivingEntity::rayTrace(double blockReachDistance, float partialTicks) return this->level->clip(vec3, vec32, false, false); -} \ No newline at end of file +} diff --git a/Minecraft.World/LivingEntity.h b/Minecraft.World/LivingEntity.h index e1275409..cdce6701 100644 --- a/Minecraft.World/LivingEntity.h +++ b/Minecraft.World/LivingEntity.h @@ -24,12 +24,12 @@ protected: // 4J - added for common ctor code void _init(); public: - // 4J-PB - added to replace (e instanceof Type), avoiding dynamic casts - eINSTANCEOF GetType() { return eTYPE_LIVINGENTITY;} - static Entity *create(Level *level) { return nullptr; } + + eINSTANCEOF GetType() { return eTYPE_LIVINGENTITY; } + static Entity* create(Level* level) { return nullptr; } private: - static AttributeModifier *SPEED_MODIFIER_SPRINTING; + static AttributeModifier* SPEED_MODIFIER_SPRINTING; public: static const int SLOT_WEAPON = 0; @@ -51,9 +51,9 @@ public: static const int DATA_ARROW_COUNT_ID = 9; private: - BaseAttributeMap *attributes; - CombatTracker *combatTracker; - unordered_map activeEffects; + BaseAttributeMap* attributes; + CombatTracker* combatTracker; + unordered_map activeEffects; ItemInstanceArray lastEquipment; public: @@ -143,7 +143,7 @@ protected: virtual bool isAlwaysExperienceDropper(); public: - virtual Random *getRandom(); + virtual Random* getRandom(); virtual shared_ptr getLastHurtByMob(); virtual int getLastHurtByMobTimestamp(); virtual void setLastHurtByMob(shared_ptr hurtBy); @@ -151,37 +151,37 @@ public: virtual int getLastHurtMobTimestamp(); virtual void setLastHurtMob(shared_ptr target); virtual int getNoActionTime(); - virtual void addAdditonalSaveData(CompoundTag *entityTag); - virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag* entityTag); + virtual void readAdditionalSaveData(CompoundTag* tag); protected: virtual void tickEffects(); public: virtual void removeAllEffects(); - virtual vector *getActiveEffects(); + virtual vector* getActiveEffects(); virtual bool hasEffect(int id); - virtual bool hasEffect(MobEffect *effect); - virtual MobEffectInstance *getEffect(MobEffect *effect); - virtual void addEffect(MobEffectInstance *newEffect); - virtual void addEffectNoUpdate(MobEffectInstance *newEffect); // 4J added - virtual bool canBeAffected(MobEffectInstance *newEffect); + virtual bool hasEffect(MobEffect* effect); + virtual MobEffectInstance* getEffect(MobEffect* effect); + virtual void addEffect(MobEffectInstance* newEffect); + virtual void addEffectNoUpdate(MobEffectInstance* newEffect); // 4J added + virtual bool canBeAffected(MobEffectInstance* newEffect); virtual bool isInvertedHealAndHarm(); virtual void removeEffectNoUpdate(int effectId); virtual void removeEffect(int effectId); protected: - virtual void onEffectAdded(MobEffectInstance *effect); - virtual void onEffectUpdated(MobEffectInstance *effect, bool doRefreshAttributes); - virtual void onEffectRemoved(MobEffectInstance *effect); + virtual void onEffectAdded(MobEffectInstance* effect); + virtual void onEffectUpdated(MobEffectInstance* effect, bool doRefreshAttributes); + virtual void onEffectRemoved(MobEffectInstance* effect); public: virtual void heal(float heal); virtual float getHealth(); virtual void setHealth(float health); - virtual bool hurt(DamageSource *source, float dmg); + virtual bool hurt(DamageSource* source, float dmg); virtual void breakItem(shared_ptr itemInstance); - virtual void die(DamageSource *source); + virtual void die(DamageSource* source); protected: virtual void dropEquipment(bool byPlayer, int playerBonusLevel); @@ -208,12 +208,12 @@ public: protected: virtual void hurtArmor(float damage); - virtual float getDamageAfterArmorAbsorb(DamageSource *damageSource, float damage); - virtual float getDamageAfterMagicAbsorb(DamageSource *damageSource, float damage); - virtual void actuallyHurt(DamageSource *source, float dmg); + virtual float getDamageAfterArmorAbsorb(DamageSource* damageSource, float damage); + virtual float getDamageAfterMagicAbsorb(DamageSource* damageSource, float damage); + virtual void actuallyHurt(DamageSource* source, float dmg); public: - virtual CombatTracker *getCombatTracker(); + virtual CombatTracker* getCombatTracker(); virtual shared_ptr getKillCredit(); virtual float getMaxHealth(); virtual int getArrowCount(); @@ -231,8 +231,8 @@ protected: virtual void updateSwingTime(); public: - virtual AttributeInstance *getAttribute(Attribute *attribute); - virtual BaseAttributeMap *getAttributes(); + virtual AttributeInstance* getAttribute(Attribute* attribute); + virtual BaseAttributeMap* getAttributes(); virtual MobType getMobType(); virtual shared_ptr getCarriedItem() = 0; @@ -243,7 +243,7 @@ public: virtual ItemInstanceArray getEquipmentSlots() = 0; - virtual Icon *getItemInHandIcon(shared_ptr item, int layer); + virtual Icon* getItemInHandIcon(shared_ptr item, int layer); protected: virtual float getSoundVolume(); @@ -255,7 +255,7 @@ public: protected: virtual void findStandUpPosition(shared_ptr vehicle); - + public: virtual bool shouldShowName(); @@ -303,12 +303,12 @@ public: public: - virtual Vec3 *getLookAngle(); - virtual Vec3 *getViewVector(float a); + virtual Vec3* getLookAngle(); + virtual Vec3* getViewVector(float a); virtual float getAttackAnim(float a); - virtual Vec3 *getPos(float a); - virtual HitResult *pick(double range, float a); - virtual bool isEffectiveAi(); + virtual Vec3* getPos(float a); + virtual HitResult* pick(double range, float a); + virtual bool isEffectiveAi()const; virtual bool isPickable(); virtual bool isPushable(); @@ -323,12 +323,13 @@ public: virtual float getAbsorptionAmount(); virtual void setAbsorptionAmount(float absorptionAmount); - virtual Team *getTeam(); + virtual Team* getTeam(); virtual bool isAlliedTo(shared_ptr other); - virtual bool isAlliedTo(Team *other); + virtual bool isAlliedTo(Team* other); public: - virtual float getEyeHeight(); - virtual Vec3 *getPositionEyes(float partialTicks); - virtual HitResult *rayTrace(double blockReachDistance, float partialTicks); + virtual float getEyeHeight(); + virtual Vec3* getPositionEyes(float partialTicks); + virtual HitResult* rayTrace(double blockReachDistance, float partialTicks); + }; diff --git a/Minecraft.World/Player.cpp b/Minecraft.World/Player.cpp index 85cac0c5..d6b9b9ed 100644 --- a/Minecraft.World/Player.cpp +++ b/Minecraft.World/Player.cpp @@ -2794,6 +2794,47 @@ unsigned int Player::getPlayerGamePrivilege(unsigned int uiGamePrivileges, EPlay 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) { Player::setPlayerGamePrivilege(m_uiGamePrivileges,privilege,value); @@ -3204,3 +3245,8 @@ void Player::SetPlayerNameValidState(bool bState) } } #endif + +bool Player::isSpectator() +{ + return false; +} \ No newline at end of file diff --git a/Minecraft.World/Player.h b/Minecraft.World/Player.h index 84249bde..c74305d7 100644 --- a/Minecraft.World/Player.h +++ b/Minecraft.World/Player.h @@ -503,6 +503,7 @@ private: unsigned int getPlayerGamePrivilege(EPlayerGamePrivileges privilege); public: + static _SkinAdjustments getSkinAdjustmentsById(unsigned int skinId); unsigned int getAllPlayerGamePrivileges() { return getPlayerGamePrivilege(ePlayerGamePrivilege_All); } static unsigned int getPlayerGamePrivilege(unsigned int uiGamePrivileges, EPlayerGamePrivileges privilege); @@ -522,6 +523,7 @@ public: bool hasInvisiblePrivilege(); bool hasInvulnerablePrivilege(); bool isModerator(); + bool isSpectator(); static void enableAllPlayerPrivileges(unsigned int &uigamePrivileges, bool enable); void enableAllPlayerPrivileges(bool enable); diff --git a/Minecraft.World/Rotations.cpp b/Minecraft.World/Rotations.cpp new file mode 100644 index 00000000..f2fee2d8 --- /dev/null +++ b/Minecraft.World/Rotations.cpp @@ -0,0 +1,22 @@ +#include "stdafx.h" +#include "Rotations.h" +#include "ListTag.h" +#include "FloatTag.h" + + +Rotations::Rotations(ListTag* list) +{ + x = list->get(0)->data; + y = list->get(1)->data; + z = list->get(2)->data; +} + + +ListTag* Rotations::save() const +{ + ListTag* tag = new ListTag(); + tag->add(new FloatTag(L"", x)); + tag->add(new FloatTag(L"", y)); + tag->add(new FloatTag(L"", z)); + return tag; +} \ No newline at end of file diff --git a/Minecraft.World/Rotations.h b/Minecraft.World/Rotations.h new file mode 100644 index 00000000..e77e1cfe --- /dev/null +++ b/Minecraft.World/Rotations.h @@ -0,0 +1,44 @@ +#pragma once +#include +using namespace std; + + +template 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* 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* save() const; +}; \ No newline at end of file diff --git a/Minecraft.World/SynchedEntityData.cpp b/Minecraft.World/SynchedEntityData.cpp index 67b9597b..a251b554 100644 --- a/Minecraft.World/SynchedEntityData.cpp +++ b/Minecraft.World/SynchedEntityData.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Class.h" #include "BasicTypeContainers.h" #include "InputOutputStream.h" @@ -7,619 +7,344 @@ #include "net.minecraft.world.item.h" #include "SynchedEntityData.h" - SynchedEntityData::SynchedEntityData() { - m_isDirty = false; - m_isEmpty = true; + m_isDirty = false; + m_isEmpty = true; } + + void SynchedEntityData::define(int id, int value) { - MemSect(17); - checkId(id); - int type = TYPE_INT; - shared_ptr dataItem = std::make_shared(type, id, value); - itemsById[id] = dataItem; - MemSect(0); - m_isEmpty = false; + MemSect(17); + checkId(id); + itemsById[id] = std::make_shared(TYPE_INT, id, value); + MemSect(0); + m_isEmpty = false; } void SynchedEntityData::define(int id, byte value) { - MemSect(17); - checkId(id); - int type = TYPE_BYTE; - shared_ptr dataItem = std::make_shared(type, id, value); - itemsById[id] = dataItem; - MemSect(0); - m_isEmpty = false; + MemSect(17); + checkId(id); + itemsById[id] = std::make_shared(TYPE_BYTE, id, value); + MemSect(0); + m_isEmpty = false; } void SynchedEntityData::define(int id, short value) { - MemSect(17); - checkId(id); - int type = TYPE_SHORT; - shared_ptr dataItem = std::make_shared(type, id, value); - itemsById[id] = dataItem; - MemSect(0); - m_isEmpty = false; + MemSect(17); + checkId(id); + itemsById[id] = std::make_shared(TYPE_SHORT, id, value); + MemSect(0); + m_isEmpty = false; } void SynchedEntityData::define(int id, float value) { - MemSect(17); - checkId(id); - int type = TYPE_FLOAT; - shared_ptr dataItem = std::make_shared(type, id, value); - itemsById[id] = dataItem; - MemSect(0); - m_isEmpty = false; + MemSect(17); + checkId(id); + itemsById[id] = std::make_shared(TYPE_FLOAT, id, value); + MemSect(0); + m_isEmpty = false; } void SynchedEntityData::define(int id, const wstring& value) { - MemSect(17); - checkId(id); - int type = TYPE_STRING; - shared_ptr dataItem = std::make_shared(type, id, value); - itemsById[id] = dataItem; - MemSect(0); - m_isEmpty = false; + MemSect(17); + checkId(id); + itemsById[id] = std::make_shared(TYPE_STRING, id, value); + MemSect(0); + m_isEmpty = false; } -void SynchedEntityData::defineNULL(int id, void *pVal) +void SynchedEntityData::define(int id, const Rotations& value) { - MemSect(17); - checkId(id); - int type = TYPE_ITEMINSTANCE; - shared_ptr dataItem = std::make_shared(type, id, shared_ptr()); - itemsById[id] = dataItem; - MemSect(0); - m_isEmpty = false; + MemSect(17); + checkId(id); + itemsById[id] = std::make_shared(TYPE_ROTATIONS, id, value); + MemSect(0); + m_isEmpty = false; +} + +void SynchedEntityData::defineNULL(int id, void* pVal) +{ + MemSect(17); + checkId(id); + itemsById[id] = std::make_shared(TYPE_ITEMINSTANCE, id, shared_ptr()); + MemSect(0); + m_isEmpty = false; } void SynchedEntityData::checkId(int id) { -#if 0 - 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 + // validation disabled in shipping build } -byte SynchedEntityData::getByte(int id) + + +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) { 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(); } +shared_ptr SynchedEntityData::getItemInstance(int id) { return itemsById[id]->getValue_itemInstance(); } + +Pos* SynchedEntityData::getPos(int id) { - return itemsById[id]->getValue_byte(); + assert(false); + return nullptr; } -short SynchedEntityData::getShort(int id) +Rotations SynchedEntityData::getRotations(int id) { - return itemsById[id]->getValue_short(); + return itemsById[id]->getValue_rotations(); } -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(); -} - -shared_ptr SynchedEntityData::getItemInstance(int id) -{ - //assert(false); // 4J - not currently implemented - return itemsById[id]->getValue_itemInstance(); -} - -Pos *SynchedEntityData::getPos(int id) -{ - assert(false); // 4J - not currently implemented - return nullptr; -} void SynchedEntityData::set(int id, int value) { - shared_ptr dataItem = itemsById[id]; - - // update the value if it has changed - if (value != dataItem->getValue_int()) - { - dataItem->setValue(value); - dataItem->setDirty(true); - m_isDirty = true; - } + shared_ptr item = itemsById[id]; + if (value != item->getValue_int()) { item->setValue(value); item->setDirty(true); m_isDirty = true; } } void SynchedEntityData::set(int id, byte value) { - shared_ptr dataItem = itemsById[id]; - - // update the value if it has changed - if (value != dataItem->getValue_byte()) - { - dataItem->setValue(value); - dataItem->setDirty(true); - m_isDirty = true; - } + shared_ptr item = itemsById[id]; + if (value != item->getValue_byte()) { item->setValue(value); item->setDirty(true); m_isDirty = true; } } void SynchedEntityData::set(int id, short value) { - shared_ptr dataItem = itemsById[id]; - - // update the value if it has changed - if (value != dataItem->getValue_short()) - { - dataItem->setValue(value); - dataItem->setDirty(true); - m_isDirty = true; - } + shared_ptr item = itemsById[id]; + if (value != item->getValue_short()) { item->setValue(value); item->setDirty(true); m_isDirty = true; } } void SynchedEntityData::set(int id, float value) { - shared_ptr dataItem = itemsById[id]; - - // update the value if it has changed - if (value != dataItem->getValue_float()) - { - dataItem->setValue(value); - dataItem->setDirty(true); - m_isDirty = true; - } + shared_ptr item = itemsById[id]; + if (value != item->getValue_float()) { item->setValue(value); item->setDirty(true); m_isDirty = true; } } void SynchedEntityData::set(int id, const wstring& value) { - shared_ptr dataItem = itemsById[id]; - - // update the value if it has changed - if (value != dataItem->getValue_wstring()) - { - dataItem->setValue(value); - dataItem->setDirty(true); - m_isDirty = true; - } + shared_ptr item = itemsById[id]; + if (value != item->getValue_wstring()) { item->setValue(value); item->setDirty(true); m_isDirty = true; } } void SynchedEntityData::set(int id, shared_ptr value) { - shared_ptr dataItem = itemsById[id]; - - // update the value if it has changed - if (value != dataItem->getValue_itemInstance()) - { - dataItem->setValue(value); - dataItem->setDirty(true); - m_isDirty = true; - } + shared_ptr item = itemsById[id]; + if (value != item->getValue_itemInstance()) { item->setValue(value); item->setDirty(true); m_isDirty = true; } } -void SynchedEntityData::markDirty(int id) +void SynchedEntityData::set(int id, const Rotations& value) { - itemsById[id]->dirty = true; - m_isDirty = true; -} - -bool SynchedEntityData::isDirty() -{ - return m_isDirty; -} - -void SynchedEntityData::pack(vector > *items, DataOutputStream *output) // TODO throws IOException -{ - - if (items) - { - for (auto& dataItem : *items) - { - writeDataItem(output, dataItem); - } - } - - // add an eof - output->writeByte(EOF_MARKER); -} - -vector > *SynchedEntityData::packDirty() -{ - - vector > *result = nullptr; - - if (m_isDirty) - { - for( int i = 0; i <= MAX_ID_VALUE; i++ ) - { - shared_ptr dataItem = itemsById[i]; - if ((dataItem != nullptr) && dataItem->isDirty()) - { - dataItem->setDirty(false); - - if (result == nullptr) - { - result = new vector >(); - } - result->push_back(dataItem); - } - } - } - m_isDirty = false; - - return result; -} - -void SynchedEntityData::packAll(DataOutputStream *output) // throws IOException -{ - for( int i = 0; i <= MAX_ID_VALUE; i++ ) - { - shared_ptr dataItem = itemsById[i]; - if(dataItem != nullptr) - { - writeDataItem(output, dataItem); - } - } - - // add an eof - output->writeByte(EOF_MARKER); -} - -vector > *SynchedEntityData::getAll() -{ - vector > *result = nullptr; - - for( int i = 0; i <= MAX_ID_VALUE; i++ ) - { - shared_ptr dataItem = itemsById[i]; - if(dataItem != nullptr) - { - if (result == nullptr) - { - result = new vector >(); - } - result->push_back(dataItem); - } - } - - return result; + shared_ptr item = itemsById[id]; + if (value != item->getValue_rotations()) { item->setValue(value); item->setDirty(true); m_isDirty = true; } } -void SynchedEntityData::writeDataItem(DataOutputStream *output, shared_ptr dataItem) //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>* items, DataOutputStream* output) { - // pack type and id - int header = ((dataItem->getType() << TYPE_SHIFT) | (dataItem->getId() & MAX_ID_VALUE)) & 0xff; - output->writeByte(header); - - // write value - switch (dataItem->getType()) - { - case TYPE_BYTE: - output->writeByte( dataItem->getValue_byte()); - break; - case TYPE_INT: - output->writeInt( dataItem->getValue_int()); - break; - case TYPE_SHORT: - output->writeShort( dataItem->getValue_short()); - break; - case TYPE_FLOAT: - output->writeFloat( dataItem->getValue_float()); - break; - case TYPE_STRING: - Packet::writeUtf(dataItem->getValue_wstring(), output); - break; - case TYPE_ITEMINSTANCE: - { - shared_ptr instance = (shared_ptr )dataItem->getValue_itemInstance(); - Packet::writeItem(instance, output); - } - break; - - default: - assert(false); // 4J - not implemented - break; - } + if (items) + for (auto& item : *items) + writeDataItem(output, item); + output->writeByte(EOF_MARKER); } -vector > *SynchedEntityData::unpack(DataInputStream *input) //throws IOException +vector>* SynchedEntityData::packDirty() { + vector>* result = nullptr; + if (m_isDirty) + { + for (int i = 0; i <= MAX_ID_VALUE; i++) + { + shared_ptr item = itemsById[i]; + if (item && item->isDirty()) + { + item->setDirty(false); + if (!result) result = new vector>(); + result->push_back(item); + } + } + } + m_isDirty = false; + return result; +} - vector > *result = nullptr; +void SynchedEntityData::packAll(DataOutputStream* output) +{ + for (int i = 0; i <= MAX_ID_VALUE; i++) + if (itemsById[i]) writeDataItem(output, itemsById[i]); + output->writeByte(EOF_MARKER); +} - int currentHeader = input->readByte(); +vector>* SynchedEntityData::getAll() +{ + vector>* result = nullptr; + for (int i = 0; i <= MAX_ID_VALUE; i++) + { + if (itemsById[i]) + { + if (!result) result = new vector>(); + result->push_back(itemsById[i]); + } + } + return result; +} - int itemCount = 0; +void SynchedEntityData::writeDataItem(DataOutputStream* output, shared_ptr item) +{ + int header = ((item->getType() << TYPE_SHIFT) | (item->getId() & MAX_ID_VALUE)) & 0xff; + output->writeByte(header); + switch (item->getType()) + { + case TYPE_BYTE: output->writeByte(item->getValue_byte()); break; + case TYPE_INT: output->writeInt(item->getValue_int()); break; + case TYPE_SHORT: output->writeShort(item->getValue_short()); break; + case TYPE_FLOAT: output->writeFloat(item->getValue_float()); break; + case TYPE_STRING: Packet::writeUtf(item->getValue_wstring(), output); break; + case TYPE_ITEMINSTANCE: Packet::writeItem(item->getValue_itemInstance(), output); break; + case TYPE_ROTATIONS: + output->writeFloat(item->getValue_rotations().getX()); + output->writeFloat(item->getValue_rotations().getY()); + output->writeFloat(item->getValue_rotations().getZ()); + break; + default: assert(false); break; + } +} + +vector>* SynchedEntityData::unpack(DataInputStream* input) +{ + vector>* result = nullptr; + int currentHeader = input->readByte(); + int itemCount = 0; const int MAX_ENTITY_DATA_ITEMS = 256; while (currentHeader != EOF_MARKER && itemCount < MAX_ENTITY_DATA_ITEMS) - { + { + if (!result) result = new vector>(); + int itemType = (currentHeader & TYPE_MASK) >> TYPE_SHIFT; + int itemId = (currentHeader & MAX_ID_VALUE); + shared_ptr item; - if (result == nullptr) - { - result = new vector >(); - } - - // split type and id - int itemType = (currentHeader & TYPE_MASK) >> TYPE_SHIFT; - int itemId = (currentHeader & MAX_ID_VALUE); - - shared_ptr item = shared_ptr(); - switch (itemType) - { - case TYPE_BYTE: - { - byte dataRead = input->readByte(); - item = std::make_shared(itemType, itemId, dataRead); - } - break; - case TYPE_SHORT: - { - short dataRead = input->readShort(); - item = std::make_shared(itemType, itemId, dataRead); - } - break; - case TYPE_INT: - { - int dataRead = input->readInt(); - item = std::make_shared(itemType, itemId, dataRead); - } - break; - case TYPE_FLOAT: - { - float dataRead = input->readFloat(); - item = std::make_shared(itemType, itemId, dataRead); - - } - break; - case TYPE_STRING: - item = std::make_shared(itemType, itemId, Packet::readUtf(input, MAX_STRING_DATA_LENGTH)); - break; - case TYPE_ITEMINSTANCE: - { - item = std::make_shared(itemType, itemId, Packet::readItem(input)); - } - break; - default: - app.DebugPrintf(" ------ garbage data, or early end of stream due to an incomplete packet\n"); - delete result; - return nullptr; - break; - } - result->push_back(item); + switch (itemType) + { + case TYPE_BYTE: item = std::make_shared(itemType, itemId, (byte)input->readByte()); break; + case TYPE_SHORT: item = std::make_shared(itemType, itemId, (short)input->readShort()); break; + case TYPE_INT: item = std::make_shared(itemType, itemId, (int)input->readInt()); break; + case TYPE_FLOAT: item = std::make_shared(itemType, itemId, (float)input->readFloat()); break; + case TYPE_STRING: item = std::make_shared(itemType, itemId, Packet::readUtf(input, MAX_STRING_DATA_LENGTH)); break; + case TYPE_ITEMINSTANCE: item = std::make_shared(itemType, itemId, Packet::readItem(input)); break; + case TYPE_ROTATIONS: + { + float rx = input->readFloat(); + float ry = input->readFloat(); + float rz = input->readFloat(); + item = std::make_shared(itemType, itemId, Rotations(rx, ry, rz)); + break; + } + default: + app.DebugPrintf(" ------ garbage data, or early end of stream\n"); + delete result; + return nullptr; + } + result->push_back(item); itemCount++; - - currentHeader = input->readByte(); - } - - return result; + currentHeader = input->readByte(); + } + return result; } -/** -* Assigns values from a list of data items. -* -* @param items -*/ - -void SynchedEntityData::assignValues(vector > *items) +void SynchedEntityData::assignValues(vector>* items) { - for (auto& item : *items) - { - shared_ptr itemFromId = itemsById[item->getId()]; - if( itemFromId != nullptr ) - { - switch(item->getType()) - { - case TYPE_BYTE: - itemFromId->setValue(item->getValue_byte()); - break; - case TYPE_SHORT: - itemFromId->setValue(item->getValue_short()); - break; - case TYPE_INT: - itemFromId->setValue(item->getValue_int()); - 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; -} - -bool SynchedEntityData::isEmpty() -{ - return m_isEmpty; -} - -void SynchedEntityData::clearDirty() -{ - m_isDirty = false; + for (auto& item : *items) + { + shared_ptr dest = itemsById[item->getId()]; + if (!dest) continue; + switch (item->getType()) + { + case TYPE_BYTE: dest->setValue(item->getValue_byte()); break; + case TYPE_SHORT: dest->setValue(item->getValue_short()); break; + case TYPE_INT: dest->setValue(item->getValue_int()); break; + case TYPE_FLOAT: dest->setValue(item->getValue_float()); break; + case TYPE_STRING: dest->setValue(item->getValue_wstring()); break; + case TYPE_ITEMINSTANCE: dest->setValue(item->getValue_itemInstance()); break; + case TYPE_ROTATIONS: dest->setValue(item->getValue_rotations()); break; + default: assert(false); break; + } + } + m_isDirty = true; } int SynchedEntityData::getSizeInBytes() { - int size = 1; - - for( int i = 0; i <= MAX_ID_VALUE; i++ ) - { - shared_ptr dataItem = itemsById[i]; - if(dataItem != nullptr) - { - size += 1; - - // write value - switch (dataItem->getType()) - { - case TYPE_BYTE: - size += 1; - break; - case TYPE_SHORT: - size += 2; - break; - case TYPE_INT: - size += 4; - break; - case TYPE_FLOAT: - size += 4; - break; - case TYPE_STRING: - size += static_cast(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; + int size = 1; + for (int i = 0; i <= MAX_ID_VALUE; i++) + { + shared_ptr item = itemsById[i]; + if (!item) continue; + size += 1; + switch (item->getType()) + { + case TYPE_BYTE: size += 1; break; + case TYPE_SHORT: size += 2; break; + case TYPE_INT: size += 4; break; + case TYPE_FLOAT: size += 4; break; + case TYPE_STRING: size += (int)item->getValue_wstring().length() + 2; break; + case TYPE_ITEMINSTANCE: size += 5; break; + case TYPE_ROTATIONS: size += 12; break; + default: break; + } + } + 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 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; - this->dirty = true; + value_int = 0; + dirty = true; } -SynchedEntityData::DataItem::DataItem(int type, int id, byte value) : type( type ), id( id ) -{ - this->value_byte = value; - this->dirty = true; -} +void SynchedEntityData::DataItem::setValue(const Rotations& value) { value_rotations = value; } +Rotations SynchedEntityData::DataItem::getValue_rotations() { return value_rotations; } -SynchedEntityData::DataItem::DataItem(int type, int id, short value) : type( type ), id( id ) -{ - this->value_short = value; - this->dirty = true; -} +int SynchedEntityData::DataItem::getId() { return id; } +int SynchedEntityData::DataItem::getType() { return type; } +bool SynchedEntityData::DataItem::isDirty() { return dirty; } +void SynchedEntityData::DataItem::setDirty(bool d) { dirty = d; } -SynchedEntityData::DataItem::DataItem(int type, int id, float value) : type( type ), id( id ) -{ - this->value_float = value; - this->dirty = true; -} +void SynchedEntityData::DataItem::setValue(int v) { value_int = v; } +void SynchedEntityData::DataItem::setValue(byte v) { value_byte = v; } +void SynchedEntityData::DataItem::setValue(short v) { value_short = v; } +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 v) { value_itemInstance = v; } -SynchedEntityData::DataItem::DataItem(int type, int id, const wstring& value) : type( type ), id( id ) -{ - this->value_wstring = value; - this->dirty = true; -} - -SynchedEntityData::DataItem::DataItem(int type, int id, shared_ptr 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) -{ - 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 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; -} \ No newline at end of file +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 SynchedEntityData::DataItem::getValue_itemInstance() { return value_itemInstance; } \ No newline at end of file diff --git a/Minecraft.World/SynchedEntityData.h b/Minecraft.World/SynchedEntityData.h index 69d0f248..52a381b8 100644 --- a/Minecraft.World/SynchedEntityData.h +++ b/Minecraft.World/SynchedEntityData.h @@ -1,135 +1,129 @@ #pragma once +#include "Rotations.h" using namespace std; class Pos; - class SynchedEntityData { public: - class DataItem - { - friend class SynchedEntityData; - private: - const int type; - 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 { - byte value_byte; - int value_int; - short value_short; - float value_float; - }; - wstring value_wstring; - shared_ptr value_itemInstance; - bool dirty; + class DataItem + { + friend class SynchedEntityData; + private: + const int type; + const int id; + union { + byte value_byte; + int value_int; + short value_short; + float value_float; + }; + wstring value_wstring; + shared_ptr value_itemInstance; + bool dirty; - public: - // There was one type here that took a generic Object type, using overloading here instead - DataItem(int type, int id, byte value); - DataItem(int type, int id, int value); - DataItem(int type, int id, const wstring& value); - DataItem(int type, int id, shared_ptr itemInstance); - DataItem(int type, int id, short value); - DataItem(int type, int id, float value); + public: + Rotations value_rotations; - int getId(); - void setValue(byte value); - void setValue(int value); - void setValue(short value); - void setValue(float value); - void setValue(const wstring& value); - void setValue(shared_ptr value); - byte getValue_byte(); - int getValue_int(); - short getValue_short(); - float getValue_float(); - wstring getValue_wstring(); - shared_ptr getValue_itemInstance(); - int getType(); - bool isDirty(); - void setDirty(bool dirty); - }; + 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, int value); + DataItem(int type, int id, const wstring& value); + DataItem(int type, int id, shared_ptr itemInstance); + DataItem(int type, int id, short value); + DataItem(int type, int id, float value); + + int getId(); + void setValue(byte value); + void setValue(int value); + void setValue(short value); + void setValue(float value); + void setValue(const wstring& value); + void setValue(shared_ptr value); + byte getValue_byte(); + int getValue_int(); + short getValue_short(); + float getValue_float(); + wstring getValue_wstring(); + shared_ptr getValue_itemInstance(); + int getType(); + bool isDirty(); + void setDirty(bool dirty); + }; public: - static const int MAX_STRING_DATA_LENGTH = 64; - static const int EOF_MARKER = 0x7f; + static const int MAX_STRING_DATA_LENGTH = 64; + static const int EOF_MARKER = 0x7f; - static const int TYPE_BYTE = 0; - static const int TYPE_SHORT = 1; - static const int TYPE_INT = 2; - static const int TYPE_FLOAT = 3; - static const int TYPE_STRING = 4; - // special types (max possible value is 7): - static const int TYPE_ITEMINSTANCE = 5; - static const int TYPE_POS = 6; + static const int TYPE_BYTE = 0; + static const int TYPE_SHORT = 1; + static const int TYPE_INT = 2; + static const int TYPE_FLOAT = 3; + static const int TYPE_STRING = 4; + static const int TYPE_ITEMINSTANCE = 5; + static const int TYPE_POS = 6; + static const int TYPE_ROTATIONS = 7; 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_SHIFT = 5; + static const int TYPE_MASK = 0xe0; + static const int TYPE_SHIFT = 5; + static const int MAX_ID_VALUE = ~TYPE_MASK & 0xff; - // the id value must fit in the remaining bits - static const int MAX_ID_VALUE = ~TYPE_MASK & 0xff; - - shared_ptr itemsById[MAX_ID_VALUE+1]; - bool m_isDirty; + shared_ptr itemsById[MAX_ID_VALUE + 1]; + bool m_isDirty; 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, const wstring& value); - void define(int id, int value); - void define(int id, short value); - void define(int id, float value); - void defineNULL(int id, void *pVal); + void define(int id, byte value); + void define(int id, const wstring& value); + void define(int id, int value); + void define(int id, short value); + void define(int id, float value); + void define(int id, const Rotations& value); + void defineNULL(int id, void* pVal); - void checkId(int id); // 4J - added to contain common code from overloaded define functions above - byte getByte(int id); - short getShort(int id); - int getInteger(int id); - float getFloat(int id); - wstring getString(int id); - shared_ptr getItemInstance(int id); - Pos *getPos(int id); - // 4J - using overloads rather than template here - void set(int id, byte value); - void set(int id, int value); - void set(int id, short value); - void set(int id, float value); - void set(int id, const wstring& value); - void set(int id, shared_ptr); - void markDirty(int id); - bool isDirty(); - static void pack(vector > *items, DataOutputStream *output); // TODO throws IOException - vector > *packDirty(); - void packAll(DataOutputStream *output); // throws IOException - vector > *getAll(); + void checkId(int id); + byte getByte(int id); + short getShort(int id); + int getInteger(int id); + float getFloat(int id); + wstring getString(int id); + shared_ptr getItemInstance(int id); + Pos* getPos(int id); + + void set(int id, byte value); + void set(int id, int value); + void set(int id, short value); + void set(int id, float value); + void set(int id, const wstring& value); + void set(int id, shared_ptr); + void set(int id, const Rotations& value); + + Rotations getRotations(int id); + + void markDirty(int id); + bool isDirty(); + static void pack(vector>* items, DataOutputStream* output); + vector>* packDirty(); + void packAll(DataOutputStream* output); + vector>* getAll(); private: - static void writeDataItem(DataOutputStream *output, shared_ptr dataItem); //throws IOException - + static void writeDataItem(DataOutputStream* output, shared_ptr dataItem); public: - static vector > *unpack(DataInputStream *input); // throws IOException + static vector>* unpack(DataInputStream* input); + void assignValues(vector>* items); + bool isEmpty(); + void clearDirty(); - /** - * Assigns values from a list of data items. - * - * @param items - */ -public: - void assignValues(vector > *items); - bool isEmpty(); - void clearDirty(); - - // 4J Added - int getSizeInBytes(); + // 4J Added + int getSizeInBytes(); }; \ No newline at end of file diff --git a/Minecraft.World/Tag.cpp b/Minecraft.World/Tag.cpp index eafdc9e8..30273537 100644 --- a/Minecraft.World/Tag.cpp +++ b/Minecraft.World/Tag.cpp @@ -52,7 +52,7 @@ void Tag::print(ostream out) out << ""; } -void Tag::print(char *prefix, wostream out) +void Tag::print(char *prefix, wostream& out) { wstring name = getName(); diff --git a/Minecraft.World/Tag.h b/Minecraft.World/Tag.h index cfb125aa..fd88a99e 100644 --- a/Minecraft.World/Tag.h +++ b/Minecraft.World/Tag.h @@ -32,7 +32,7 @@ public: virtual wstring toString() = 0; virtual byte getId() = 0; void print(ostream out); - void print(char *prefix, wostream out); + void print(char *prefix, wostream& out); wstring getName(); Tag *setName(const wstring& name); static Tag *readNamedTag(DataInput *dis); diff --git a/Minecraft.World/cmake/sources/Common.cmake b/Minecraft.World/cmake/sources/Common.cmake index 1884260d..909aa605 100644 --- a/Minecraft.World/cmake/sources/Common.cmake +++ b/Minecraft.World/cmake/sources/Common.cmake @@ -145,6 +145,8 @@ set(_MINECRAFT_WORLD_COMMON_COM_MOJANG_NBT "${CMAKE_CURRENT_SOURCE_DIR}/Tag.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Tag.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})