1
0

Merge pull request #1810 from mc-server/paintings

Paintings
This commit is contained in:
Mattes D 2015-03-15 14:30:23 +01:00
commit 0add3d4617
13 changed files with 156 additions and 189 deletions

View File

@ -11,7 +11,7 @@
cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_Facing, double a_X, double a_Y, double a_Z) :
cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8),
m_Facing(a_Facing)
m_Facing(cHangingEntity::BlockFaceToProtocolFace(a_Facing))
{
SetMaxHealth(1);
SetHealth(1);
@ -21,60 +21,9 @@ cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_Facing, do
void cHangingEntity::SetFacing(eBlockFace a_Facing)
{
// Y-based faces are not allowed:
switch (a_Facing)
{
case BLOCK_FACE_NONE:
case BLOCK_FACE_YM:
case BLOCK_FACE_YP:
{
LOGWARNING("%s: Invalid facing: %d. Ignoring.", __FUNCTION__, a_Facing);
ASSERT(!"Tried to set a bad facing!");
return;
}
default: break;
}
m_Facing = a_Facing;
}
void cHangingEntity::SpawnOn(cClientHandle & a_ClientHandle)
{
int Dir = 0;
// The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
switch (m_Facing)
{
case BLOCK_FACE_ZP: Dir = 0; break;
case BLOCK_FACE_ZM: Dir = 2; break;
case BLOCK_FACE_XM: Dir = 1; break;
case BLOCK_FACE_XP: Dir = 3; break;
default:
{
LOGINFO("Invalid facing (%d) in a cHangingEntity at {%d, %d, %d}, adjusting to BLOCK_FACE_XP.",
m_Facing, (int)GetPosX(), (int)GetPosY(), (int)GetPosZ()
);
Dir = 3;
}
}
if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
{
SetYaw((Dir * 90) - 180);
}
else
{
SetYaw(Dir * 90);
}
a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch());
a_ClientHandle.SendEntityMetadata(*this);
SetYaw(GetProtocolFacing() * 90);
}

View File

@ -24,28 +24,82 @@ public:
// tolua_begin
/** Returns the direction in which the entity is facing. */
eBlockFace GetFacing() const { return m_Facing; }
eBlockFace GetFacing() const { return cHangingEntity::ProtocolFaceToBlockFace(m_Facing); }
/** Set the direction in which the entity is facing. */
void SetFacing(eBlockFace a_Facing);
/** Returns the X coord of the block in which the entity resides. */
int GetBlockX() const { return POSX_TOINT; }
/** Returns the Y coord of the block in which the entity resides. */
int GetBlockY() const { return POSY_TOINT; }
/** Returns the Z coord of the block in which the entity resides. */
int GetBlockZ() const { return POSZ_TOINT; }
void SetFacing(eBlockFace a_Facing) { m_Facing = cHangingEntity::BlockFaceToProtocolFace(a_Facing); }
// tolua_end
private:
/** Returns the direction in which the entity is facing. */
Byte GetProtocolFacing() const { return m_Facing; }
/** Set the direction in which the entity is facing. */
void SetProtocolFacing(Byte a_Facing)
{
ASSERT((a_Facing <= 3) && (a_Facing >= 0));
m_Facing = a_Facing;
}
protected:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override {}
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override
{
UNUSED(a_Dt);
UNUSED(a_Chunk);
}
eBlockFace m_Facing;
/** Converts protocol hanging item facing to eBlockFace values */
inline static eBlockFace ProtocolFaceToBlockFace(Byte a_ProtocolFace)
{
eBlockFace Dir;
// The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
switch (a_ProtocolFace)
{
case 0: Dir = BLOCK_FACE_ZP; break;
case 2: Dir = BLOCK_FACE_ZM; break;
case 1: Dir = BLOCK_FACE_XM; break;
case 3: Dir = BLOCK_FACE_XP; break;
default:
{
LOGINFO("Invalid facing (%d) in a cHangingEntity, adjusting to BLOCK_FACE_XP.", a_ProtocolFace);
ASSERT(!"Tried to convert a bad facing!");
Dir = cHangingEntity::ProtocolFaceToBlockFace(3);
}
}
return Dir;
}
/** Converts eBlockFace values to protocol hanging item faces */
inline static Byte BlockFaceToProtocolFace(eBlockFace a_BlockFace)
{
Byte Dir;
// The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
switch (a_BlockFace)
{
case BLOCK_FACE_ZP: Dir = 0; break;
case BLOCK_FACE_ZM: Dir = 2; break;
case BLOCK_FACE_XM: Dir = 1; break;
case BLOCK_FACE_XP: Dir = 3; break;
default:
{
// Uncomment when entities are initialised with their real data, instead of dummy values:
// LOGINFO("Invalid facing (%d) in a cHangingEntity, adjusting to BLOCK_FACE_XP.", a_BlockFace);
// ASSERT(!"Tried to convert a bad facing!");
Dir = cHangingEntity::BlockFaceToProtocolFace(BLOCK_FACE_XP);
}
}
return Dir;
}
Byte m_Facing;
}; // tolua_export

View File

@ -92,3 +92,14 @@ void cItemFrame::GetDrops(cItems & a_Items, cEntity * a_Killer)
void cItemFrame::SpawnOn(cClientHandle & a_ClientHandle)
{
super::SpawnOn(a_ClientHandle);
a_ClientHandle.SendSpawnObject(*this, 71, GetProtocolFacing(), (Byte)GetYaw(), (Byte)GetPitch());
a_ClientHandle.SendEntityMetadata(*this);
}

View File

@ -42,6 +42,7 @@ private:
virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
cItem m_Item;
Byte m_ItemRotation;

View File

@ -10,10 +10,9 @@
cPainting::cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z)
: cEntity(etPainting, a_X, a_Y, a_Z, 1, 1),
m_Name(a_Name),
m_Direction(a_Direction)
cPainting::cPainting(const AString & a_Name, eBlockFace a_Direction, double a_X, double a_Y, double a_Z)
: cHangingEntity(etPainting, a_Direction, a_X, a_Y, a_Z),
m_Name(a_Name)
{
}
@ -24,6 +23,7 @@ cPainting::cPainting(const AString & a_Name, int a_Direction, double a_X, double
void cPainting::SpawnOn(cClientHandle & a_Client)
{
super::SpawnOn(a_Client);
a_Client.SendPaintingSpawn(*this);
}
@ -31,16 +31,6 @@ void cPainting::SpawnOn(cClientHandle & a_Client)
void cPainting::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
UNUSED(a_Dt);
UNUSED(a_Chunk);
}
void cPainting::GetDrops(cItems & a_Items, cEntity * a_Killer)
{
if ((a_Killer != nullptr) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative())

View File

@ -1,7 +1,7 @@
#pragma once
#include "Entity.h"
#include "HangingEntity.h"
@ -9,9 +9,9 @@
// tolua_begin
class cPainting :
public cEntity
public cHangingEntity
{
typedef cEntity super;
typedef cHangingEntity super;
public:
@ -19,19 +19,14 @@ public:
CLASS_PROTODEF(cPainting)
cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z);
cPainting(const AString & a_Name, eBlockFace a_Direction, double a_X, double a_Y, double a_Z);
// tolua_begin
const AString & GetName(void) const { return m_Name; }
int GetDirection(void) const { return m_Direction; }
// tolua_end
/** Returns the protocol name of the painting */
const AString & GetName(void) const { return m_Name; } // tolua_export
private:
virtual void SpawnOn(cClientHandle & a_Client) override;
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
virtual void KilledBy(TakeDamageInfo & a_TDI) override
{
@ -40,7 +35,6 @@ private:
}
AString m_Name;
int m_Direction;
}; // tolua_export

View File

@ -21,30 +21,17 @@ public:
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
{
if (a_Dir == BLOCK_FACE_NONE)
if ((a_Dir == BLOCK_FACE_NONE) || (a_Dir == BLOCK_FACE_YM) || (a_Dir == BLOCK_FACE_YP))
{
// Client sends this if clicked on top or bottom face
// Paintings can't be flatly placed
return false;
}
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again
if (Block == E_BLOCK_AIR)
{
int Dir = 0;
// The client uses different values for painting directions and block faces. Our constants are for the block faces, so we convert them here to painting faces
switch (a_Dir)
{
case BLOCK_FACE_ZP: break; // Initialised to zero
case BLOCK_FACE_ZM: Dir = 2; break;
case BLOCK_FACE_XM: Dir = 1; break;
case BLOCK_FACE_XP: Dir = 3; break;
default: ASSERT(!"Unhandled block face when trying spawn painting!"); return false;
}
static const struct // Define all the possible painting titles
{
AString Title;
@ -78,7 +65,7 @@ public:
{ "BurningSkull" }
};
cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, Dir, a_BlockX, a_BlockY, a_BlockZ);
cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_Dir, a_BlockX, a_BlockY, a_BlockZ);
Painting->Initialize(*a_World);
if (!a_Player->IsGameModeCreative())

View File

@ -637,7 +637,7 @@ void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting)
Pkt.WriteInt(static_cast<int>(a_Painting.GetPosX()));
Pkt.WriteInt(static_cast<int>(a_Painting.GetPosY()));
Pkt.WriteInt(static_cast<int>(a_Painting.GetPosZ()));
Pkt.WriteInt(a_Painting.GetDirection());
Pkt.WriteInt(a_Painting.GetProtocolFacing());
}

View File

@ -632,19 +632,11 @@ void cProtocol180::SendPaintingSpawn(const cPainting & a_Painting)
double PosY = a_Painting.GetPosY();
double PosZ = a_Painting.GetPosZ();
switch (a_Painting.GetDirection())
{
case 0: PosZ += 1; break;
case 1: PosX -= 1; break;
case 2: PosZ -= 1; break;
case 3: PosX += 1; break;
}
cPacketizer Pkt(*this, 0x10); // Spawn Painting packet
Pkt.WriteVarInt(a_Painting.GetUniqueID());
Pkt.WriteString(a_Painting.GetName().c_str());
Pkt.WritePosition((int)PosX, (int)PosY, (int)PosZ);
Pkt.WriteChar(a_Painting.GetDirection());
Pkt.WriteChar(a_Painting.GetProtocolFacing());
}

View File

@ -36,20 +36,9 @@
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
#include "../Entities/ItemFrame.h"
#include "../Entities/Painting.h"
#include "../Mobs/Monster.h"
#include "../Mobs/Bat.h"
#include "../Mobs/Creeper.h"
#include "../Mobs/Enderman.h"
#include "../Mobs/Horse.h"
#include "../Mobs/MagmaCube.h"
#include "../Mobs/Sheep.h"
#include "../Mobs/Slime.h"
#include "../Mobs/Skeleton.h"
#include "../Mobs/Villager.h"
#include "../Mobs/Wither.h"
#include "../Mobs/Wolf.h"
#include "../Mobs/Zombie.h"
#include "../Mobs/IncludeAllMonsters.h"
@ -726,24 +715,10 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
{
m_Writer.AddInt("TileX", a_Hanging->GetBlockX());
m_Writer.AddInt("TileY", a_Hanging->GetBlockY());
m_Writer.AddInt("TileZ", a_Hanging->GetBlockZ());
switch (a_Hanging->GetFacing())
{
case BLOCK_FACE_XM: m_Writer.AddByte("Facing", 1); break;
case BLOCK_FACE_XP: m_Writer.AddByte("Facing", 3); break;
case BLOCK_FACE_ZM: m_Writer.AddByte("Facing", 2); break;
case BLOCK_FACE_ZP: m_Writer.AddByte("Facing", 0); break;
case BLOCK_FACE_YM:
case BLOCK_FACE_YP:
case BLOCK_FACE_NONE:
{
// These directions are invalid, but they may have been previously loaded, so keep them.
break;
}
}
m_Writer.AddInt("TileX", FloorC(a_Hanging->GetPosX()));
m_Writer.AddInt("TileY", FloorC(a_Hanging->GetPosY()));
m_Writer.AddInt("TileZ", FloorC(a_Hanging->GetPosZ()));
m_Writer.AddByte("Facing", a_Hanging->GetProtocolFacing());
}
@ -790,6 +765,19 @@ void cNBTChunkSerializer::AddItemFrameEntity(cItemFrame * a_ItemFrame)
void cNBTChunkSerializer::AddPaintingEntity(cPainting * a_Painting)
{
m_Writer.BeginCompound("");
AddBasicEntity(a_Painting, "Painting");
AddHangingEntity(a_Painting);
m_Writer.AddString("Motive", a_Painting->GetName());
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{
m_Writer.BeginList("Items", TAG_Compound);
@ -888,7 +876,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
case cEntity::etTNT: AddTNTEntity ((cTNTEntity *) a_Entity); break;
case cEntity::etExpOrb: AddExpOrbEntity ((cExpOrb *) a_Entity); break;
case cEntity::etItemFrame: AddItemFrameEntity ((cItemFrame *) a_Entity); break;
case cEntity::etPainting: /* TODO */ break;
case cEntity::etPainting: AddPaintingEntity (reinterpret_cast<cPainting *>(a_Entity)); break;
case cEntity::etPlayer: return; // Players aren't saved into the world
default:
{

View File

@ -48,6 +48,7 @@ class cTNTEntity;
class cExpOrb;
class cHangingEntity;
class cItemFrame;
class cPainting;
class cEntityEffect;
@ -123,6 +124,7 @@ protected:
void AddTNTEntity (cTNTEntity * a_TNT);
void AddExpOrbEntity (cExpOrb * a_ExpOrb);
void AddItemFrameEntity (cItemFrame * a_ItemFrame);
void AddPaintingEntity (cPainting * a_Painting);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);

View File

@ -50,6 +50,7 @@
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
#include "../Entities/ItemFrame.h"
#include "../Entities/Painting.h"
#include "../Protocol/MojangAPI.h"
#include "Server.h"
@ -1337,6 +1338,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
else if (strncmp(a_IDTag, "Painting", a_IDTagLength) == 0)
{
LoadPaintingFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
{
LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
@ -1747,52 +1752,22 @@ void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT
{
// "Facing" tag is the prime source of the Facing; if not available, translate from older "Direction" or "Dir"
int Facing = a_NBT.FindChildByName(a_TagIdx, "Facing");
if (Facing > 0)
if (Facing < 0)
{
Facing = (int)a_NBT.GetByte(Facing);
if ((Facing >= 2) && (Facing <= 5))
{
a_Hanging.SetFacing(static_cast<eBlockFace>(Facing));
}
}
else
{
Facing = a_NBT.FindChildByName(a_TagIdx, "Direction");
if (Facing > 0)
{
switch ((int)a_NBT.GetByte(Facing))
{
case 0: a_Hanging.SetFacing(BLOCK_FACE_ZM); break;
case 1: a_Hanging.SetFacing(BLOCK_FACE_XM); break;
case 2: a_Hanging.SetFacing(BLOCK_FACE_ZP); break;
case 3: a_Hanging.SetFacing(BLOCK_FACE_XP); break;
}
}
else
{
Facing = a_NBT.FindChildByName(a_TagIdx, "Dir"); // Has values 0 and 2 swapped
if (Facing > 0)
{
switch ((int)a_NBT.GetByte(Facing))
{
case 0: a_Hanging.SetFacing(BLOCK_FACE_ZP); break;
case 1: a_Hanging.SetFacing(BLOCK_FACE_XM); break;
case 2: a_Hanging.SetFacing(BLOCK_FACE_ZM); break;
case 3: a_Hanging.SetFacing(BLOCK_FACE_XP); break;
}
}
}
return;
}
a_Hanging.SetProtocolFacing(a_NBT.GetByte(Facing));
int TileX = a_NBT.FindChildByName(a_TagIdx, "TileX");
int TileY = a_NBT.FindChildByName(a_TagIdx, "TileY");
int TileZ = a_NBT.FindChildByName(a_TagIdx, "TileZ");
if ((TileX > 0) && (TileY > 0) && (TileZ > 0))
{
a_Hanging.SetPosition(
(double)a_NBT.GetInt(TileX),
(double)a_NBT.GetInt(TileY),
(double)a_NBT.GetInt(TileZ)
static_cast<double>(a_NBT.GetInt(TileX)),
static_cast<double>(a_NBT.GetInt(TileY)),
static_cast<double>(a_NBT.GetInt(TileZ))
);
}
}
@ -1838,6 +1813,29 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadPaintingFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
// Load painting name:
int MotiveTag = a_NBT.FindChildByName(a_TagIdx, "Motive");
if ((MotiveTag < 0) || (a_NBT.GetType(MotiveTag) != TAG_String))
{
return;
}
std::unique_ptr<cPainting> Painting(new cPainting(a_NBT.GetString(MotiveTag), BLOCK_FACE_NONE, 0.0, 0.0, 0.0));
if (!LoadEntityBaseFromNBT(*Painting.get(), a_NBT, a_TagIdx))
{
return;
}
LoadHangingFromNBT(*Painting.get(), a_NBT, a_TagIdx);
a_Entities.push_back(Painting.release());
}
void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::unique_ptr<cArrowEntity> Arrow(new cArrowEntity(nullptr, 0, 0, 0, Vector3d(0, 0, 0)));

View File

@ -166,6 +166,7 @@ protected:
void LoadExpOrbFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadHangingFromNBT (cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadItemFrameFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPaintingFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);