1
0
Fork 0

Pickups are now being saved into Anvil.

Also changed cEntity rotation datatype to double

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1262 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2013-03-09 14:35:43 +00:00
parent ef65bd6f49
commit 7593707713
33 changed files with 1227 additions and 449 deletions

View File

@ -1634,6 +1634,14 @@
RelativePath="..\source\WorldStorage\FastNBT.h"
>
</File>
<File
RelativePath="..\source\WorldStorage\NBTChunkSerializer.cpp"
>
</File>
<File
RelativePath="..\source\WorldStorage\NBTChunkSerializer.h"
>
</File>
<File
RelativePath="..\source\WorldStorage\WorldStorage.cpp"
>

View File

@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 03/04/13 22:33:20.
** Generated automatically by tolua++-1.0.92 on 03/09/13 15:33:58.
*/
#ifndef __cplusplus
@ -257,7 +257,7 @@ static int tolua_AllToLua_cStairs_RotationToMetaData00(lua_State* tolua_S)
else
#endif
{
float a_Rotation = ((float) tolua_tonumber(tolua_S,2,0));
double a_Rotation = ((double) tolua_tonumber(tolua_S,2,0));
{
unsigned char tolua_ret = (unsigned char) cStairs::RotationToMetaData(a_Rotation);
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
@ -4365,8 +4365,8 @@ static int tolua_AllToLua_cEntity_GetRot00(lua_State* tolua_S)
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetRot'", NULL);
#endif
{
const Vector3f& tolua_ret = (const Vector3f&) self->GetRot();
tolua_pushusertype(tolua_S,(void*)&tolua_ret,"const Vector3f");
const Vector3d& tolua_ret = (const Vector3d&) self->GetRot();
tolua_pushusertype(tolua_S,(void*)&tolua_ret,"const Vector3d");
}
}
return 1;
@ -4397,7 +4397,7 @@ static int tolua_AllToLua_cEntity_GetRotation00(lua_State* tolua_S)
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetRotation'", NULL);
#endif
{
float tolua_ret = (float) self->GetRotation();
double tolua_ret = (double) self->GetRotation();
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
}
}
@ -4429,7 +4429,7 @@ static int tolua_AllToLua_cEntity_GetPitch00(lua_State* tolua_S)
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPitch'", NULL);
#endif
{
float tolua_ret = (float) self->GetPitch();
double tolua_ret = (double) self->GetPitch();
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
}
}
@ -4461,7 +4461,7 @@ static int tolua_AllToLua_cEntity_GetRoll00(lua_State* tolua_S)
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetRoll'", NULL);
#endif
{
float tolua_ret = (float) self->GetRoll();
double tolua_ret = (double) self->GetRoll();
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
}
}
@ -4493,15 +4493,15 @@ static int tolua_AllToLua_cEntity_GetLookVector00(lua_State* tolua_S)
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetLookVector'", NULL);
#endif
{
Vector3f tolua_ret = (Vector3f) self->GetLookVector();
Vector3d tolua_ret = (Vector3d) self->GetLookVector();
{
#ifdef __cplusplus
void* tolua_obj = Mtolua_new((Vector3f)(tolua_ret));
tolua_pushusertype(tolua_S,tolua_obj,"Vector3f");
void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret));
tolua_pushusertype(tolua_S,tolua_obj,"Vector3d");
tolua_register_gc(tolua_S,lua_gettop(tolua_S));
#else
void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3f));
tolua_pushusertype(tolua_S,tolua_obj,"Vector3f");
void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d));
tolua_pushusertype(tolua_S,tolua_obj,"Vector3d");
tolua_register_gc(tolua_S,lua_gettop(tolua_S));
#endif
}
@ -4953,7 +4953,7 @@ static int tolua_AllToLua_cEntity_SetRotation00(lua_State* tolua_S)
#endif
{
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
float a_Rotation = ((float) tolua_tonumber(tolua_S,2,0));
double a_Rotation = ((double) tolua_tonumber(tolua_S,2,0));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetRotation'", NULL);
#endif
@ -4986,7 +4986,7 @@ static int tolua_AllToLua_cEntity_SetPitch00(lua_State* tolua_S)
#endif
{
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
float a_Pitch = ((float) tolua_tonumber(tolua_S,2,0));
double a_Pitch = ((double) tolua_tonumber(tolua_S,2,0));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetPitch'", NULL);
#endif
@ -5019,7 +5019,7 @@ static int tolua_AllToLua_cEntity_SetRoll00(lua_State* tolua_S)
#endif
{
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
float a_Roll = ((float) tolua_tonumber(tolua_S,2,0));
double a_Roll = ((double) tolua_tonumber(tolua_S,2,0));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetRoll'", NULL);
#endif
@ -5036,6 +5036,71 @@ static int tolua_AllToLua_cEntity_SetRoll00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
/* method: SetSpeed of class cEntity */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetSpeed00
static int tolua_AllToLua_cEntity_SetSpeed00(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
if (
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
!tolua_isnumber(tolua_S,2,0,&tolua_err) ||
!tolua_isnumber(tolua_S,3,0,&tolua_err) ||
!tolua_isnumber(tolua_S,4,0,&tolua_err) ||
!tolua_isnoobj(tolua_S,5,&tolua_err)
)
goto tolua_lerror;
else
#endif
{
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
double a_SpeedX = ((double) tolua_tonumber(tolua_S,2,0));
double a_SpeedY = ((double) tolua_tonumber(tolua_S,3,0));
double a_SpeedZ = ((double) tolua_tonumber(tolua_S,4,0));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetSpeed'", NULL);
#endif
{
self->SetSpeed(a_SpeedX,a_SpeedY,a_SpeedZ);
}
}
return 0;
#ifndef TOLUA_RELEASE
tolua_lerror:
tolua_error(tolua_S,"#ferror in function 'SetSpeed'.",&tolua_err);
return 0;
#endif
}
#endif //#ifndef TOLUA_DISABLE
/* method: SetSpeed of class cEntity */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetSpeed01
static int tolua_AllToLua_cEntity_SetSpeed01(lua_State* tolua_S)
{
tolua_Error tolua_err;
if (
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
(tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const Vector3d",0,&tolua_err)) ||
!tolua_isnoobj(tolua_S,3,&tolua_err)
)
goto tolua_lerror;
else
{
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
const Vector3d* a_Speed = ((const Vector3d*) tolua_tousertype(tolua_S,2,0));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetSpeed'", NULL);
#endif
{
self->SetSpeed(*a_Speed);
}
}
return 0;
tolua_lerror:
return tolua_AllToLua_cEntity_SetSpeed00(tolua_S);
}
#endif //#ifndef TOLUA_DISABLE
/* method: AddSpeed of class cEntity */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_AddSpeed00
static int tolua_AllToLua_cEntity_AddSpeed00(lua_State* tolua_S)
@ -21731,6 +21796,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_constant(tolua_S,"etEntity",cEntity::etEntity);
tolua_constant(tolua_S,"etPlayer",cEntity::etPlayer);
tolua_constant(tolua_S,"etPickup",cEntity::etPickup);
tolua_constant(tolua_S,"etMonster",cEntity::etMonster);
tolua_constant(tolua_S,"etMob",cEntity::etMob);
tolua_constant(tolua_S,"etFallingBlock",cEntity::etFallingBlock);
tolua_constant(tolua_S,"etMinecart",cEntity::etMinecart);
@ -21773,6 +21839,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"SetRotation",tolua_AllToLua_cEntity_SetRotation00);
tolua_function(tolua_S,"SetPitch",tolua_AllToLua_cEntity_SetPitch00);
tolua_function(tolua_S,"SetRoll",tolua_AllToLua_cEntity_SetRoll00);
tolua_function(tolua_S,"SetSpeed",tolua_AllToLua_cEntity_SetSpeed00);
tolua_function(tolua_S,"SetSpeed",tolua_AllToLua_cEntity_SetSpeed01);
tolua_function(tolua_S,"AddSpeed",tolua_AllToLua_cEntity_AddSpeed00);
tolua_function(tolua_S,"GetUniqueID",tolua_AllToLua_cEntity_GetUniqueID00);
tolua_function(tolua_S,"IsDestroyed",tolua_AllToLua_cEntity_IsDestroyed00);

View File

@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 03/04/13 22:33:20.
** Generated automatically by tolua++-1.0.92 on 03/09/13 15:33:59.
*/
/* Exported function */

View File

@ -47,14 +47,14 @@ public:
// Bed specific helper functions
static NIBBLETYPE RotationToMetaData(float a_Rotation)
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
a_Rotation += 180 + (180/4); // So its not aligned with axis
if( a_Rotation > 360.f ) a_Rotation -= 360.f;
if( a_Rotation > 360 ) a_Rotation -= 360;
a_Rotation = (a_Rotation/360) * 4;
a_Rotation = (a_Rotation / 360) * 4;
return ((char)a_Rotation+2) % 4;
return ((char)a_Rotation + 2) % 4;
}

View File

@ -41,7 +41,7 @@ public:
{
return false;
}
float rot = a_Player->GetRotation();
double rot = a_Player->GetRotation();
if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
@ -79,7 +79,7 @@ public:
return;
}
float rot = a_Player->GetRotation();
double rot = a_Player->GetRotation();
// Choose meta from player rotation, choose only between 2 or 3
NIBBLETYPE NewMeta = ((rot >= -90) && (rot < 90)) ? 2 : 3;
if (
@ -178,7 +178,7 @@ public:
/// Translates player rotation when placing a chest into the chest block metadata. Valid for single chests only
static NIBBLETYPE RotationToMetaData(float a_Rotation)
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
a_Rotation += 90 + 45; // So its not aligned with axis

View File

@ -28,6 +28,8 @@ public:
) override
{
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for dispenser placement!
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), 0);
return true;
}

View File

@ -35,7 +35,7 @@ public:
{
NIBBLETYPE OldMetaData = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
NIBBLETYPE NewMetaData = cDoors::RotationToMetaData(a_Player->GetRotation() + 270);
OldMetaData ^= 4; //Toggle the gate
OldMetaData ^= 4; // Toggle the gate
if ((OldMetaData & 1) == (NewMetaData & 1))
{
// Standing in front of the gate - apply new direction

View File

@ -34,7 +34,10 @@ public:
) override
{
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for furnace placement!
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), 0);
return true;
}
} ;

View File

@ -296,6 +296,12 @@ void cChunk::SetAllData(
CalculateHeightmap();
}
// Initialize incoming entities:
for (cEntityList::iterator itr = a_Entities.begin(), end = a_Entities.end(); itr != end; ++itr)
{
(*itr)->Initialize(m_World);
} // for itr - a_Entities[]
// Append entities to current entity list:
m_Entities.splice(m_Entities.end(), a_Entities);

View File

@ -204,13 +204,13 @@ inline void AddFaceDirection(int & a_BlockX, unsigned char & a_BlockY, int & a_B
#define PI 3.14159265358979323846264338327950288419716939937510582097494459072381640628620899862803482534211706798f
#define MIN(a,b) (((a)>(b))?(b):(a))
#define MAX(a,b) (((a)>(b))?(a):(b))
inline void EulerToVector( float a_Pan, float a_Pitch, float & a_X, float & a_Y, float & a_Z )
inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a_Y, double & a_Z)
{
// a_X = sinf ( a_Pan / 180 * PI ) * cosf ( a_Pitch / 180 * PI );
// a_Y = -sinf ( a_Pitch / 180 * PI );
// a_Z = -cosf ( a_Pan / 180 * PI ) * cosf ( a_Pitch / 180 * PI );
a_X = cos(a_Pan / 180 * PI)*cos(a_Pitch / 180 * PI);
a_Y = sin(a_Pan / 180 * PI)*cos(a_Pitch / 180 * PI);
a_X = cos(a_Pan / 180 * PI) * cos(a_Pitch / 180 * PI);
a_Y = sin(a_Pan / 180 * PI) * cos(a_Pitch / 180 * PI);
a_Z = sin(a_Pitch / 180 * PI);
}
@ -218,22 +218,26 @@ inline void EulerToVector( float a_Pan, float a_Pitch, float & a_X, float & a_Y,
inline void VectorToEuler( float a_X, float a_Y, float a_Z, float & a_Pan, float & a_Pitch )
inline void VectorToEuler(double a_X, double a_Y, double a_Z, double & a_Pan, double & a_Pitch)
{
if( a_X != 0 )
a_Pan = atan2( a_Z, a_X ) * 180 / PI - 90;
if (a_X != 0)
{
a_Pan = atan2(a_Z, a_X) * 180 / PI - 90;
}
else
{
a_Pan = 0;
a_Pitch = atan2(a_Y, sqrtf((a_X * a_X) + (a_Z * a_Z))) * 180 / PI;
}
a_Pitch = atan2(a_Y, sqrt((a_X * a_X) + (a_Z * a_Z))) * 180 / PI;
}
inline float GetSignf( float a_Val )
inline float GetSignf(float a_Val)
{
return (a_Val < 0.f)?-1.f:1.f;
return (a_Val < 0.f) ? -1.f : 1.f;
}
@ -242,7 +246,7 @@ inline float GetSignf( float a_Val )
inline float GetSpecialSignf( float a_Val )
{
return (a_Val <= 0.f)?-1.f:1.f;
return (a_Val <= 0.f) ? -1.f : 1.f;
}

View File

@ -1,61 +1,87 @@
#pragma once
class cDoors // tolua_export
{ // tolua_export
public:
static char RotationToMetaData( float a_Rotation ) // tolua_export
{ // tolua_export
a_Rotation += 90 + 45; // So its not aligned with axis
if( a_Rotation > 360.f ) a_Rotation -= 360.f;
if( a_Rotation >= 0.f && a_Rotation < 90.f )
return 0x0;
else if( a_Rotation >= 180 && a_Rotation < 270 )
return 0x2;
else if( a_Rotation >= 90 && a_Rotation < 180 )
return 0x1;
else
return 0x3;
} // tolua_export
static char ChangeStateMetaData( char a_MetaData ) // tolua_export
{ // tolua_export
// tolua_begin
class cDoors
{
public:
static char RotationToMetaData(double a_Rotation)
{
a_Rotation += 90 + 45; // So its not aligned with axis
if (a_Rotation > 360)
{
a_Rotation -= 360;
}
if (a_Rotation >= 0.f && a_Rotation < 90)
{
return 0x0;
}
else if ((a_Rotation >= 180) && (a_Rotation < 270))
{
return 0x2;
}
else if ((a_Rotation >= 90) && (a_Rotation < 180))
{
return 0x1;
}
else
{
return 0x3;
}
}
static NIBBLETYPE ChangeStateMetaData(NIBBLETYPE a_MetaData)
{
a_MetaData ^= 4; //XOR bit 2 aka 3. bit (Door open state)
return a_MetaData;
} // tolua_export
}
static void ChangeDoor(cWorld *a_World, int a_X, int a_Y, int a_Z) // tolua_export
{ // tolua_export
char OldMetaData = a_World->GetBlockMeta(a_X, a_Y, a_Z);
static void ChangeDoor(cWorld * a_World, int a_X, int a_Y, int a_Z)
{
NIBBLETYPE OldMetaData = a_World->GetBlockMeta(a_X, a_Y, a_Z);
a_World->SetBlockMeta(a_X, a_Y, a_Z, ChangeStateMetaData ( OldMetaData ) );
a_World->SetBlockMeta(a_X, a_Y, a_Z, ChangeStateMetaData(OldMetaData));
if (OldMetaData & 8)
{ //current block is top of the door
char BottomBlock = a_World->GetBlock(a_X, a_Y - 1, a_Z);
char BottomMeta = a_World->GetBlockMeta(a_X, a_Y - 1, a_Z);
{
// Current block is top of the door
BLOCKTYPE BottomBlock = a_World->GetBlock(a_X, a_Y - 1, a_Z);
NIBBLETYPE BottomMeta = a_World->GetBlockMeta(a_X, a_Y - 1, a_Z);
if (IsDoor(BottomBlock) && !(BottomMeta & 8))
{
a_World->SetBlockMeta(a_X, a_Y - 1, a_Z, ChangeStateMetaData ( BottomMeta ) );
a_World->SetBlockMeta(a_X, a_Y - 1, a_Z, ChangeStateMetaData(BottomMeta));
}
} else { //current block is bottom of the door
char TopBlock = a_World->GetBlock(a_X, a_Y + 1, a_Z);
char TopMeta = a_World->GetBlockMeta(a_X, a_Y + 1, a_Z);
}
else
{
// Current block is bottom of the door
BLOCKTYPE TopBlock = a_World->GetBlock(a_X, a_Y + 1, a_Z);
NIBBLETYPE TopMeta = a_World->GetBlockMeta(a_X, a_Y + 1, a_Z);
if (IsDoor(TopBlock) && (TopMeta & 8))
{
a_World->SetBlockMeta(a_X, a_Y + 1, a_Z, ChangeStateMetaData ( TopMeta ) );
a_World->SetBlockMeta(a_X, a_Y + 1, a_Z, ChangeStateMetaData(TopMeta));
}
}
} // tolua_export
inline static bool IsDoor(char a_Block)
{
return (a_Block == E_BLOCK_WOODEN_DOOR || a_Block == E_BLOCK_IRON_DOOR);
}
inline static bool IsDoor(BLOCKTYPE a_Block)
{
return (a_Block == E_BLOCK_WOODEN_DOOR) || (a_Block == E_BLOCK_IRON_DOOR);
}
} ;
// tolua_end
}; // tolua_export

View File

@ -6,7 +6,6 @@
#include "Server.h"
#include "Root.h"
#include "Vector3d.h"
#include "Vector3f.h"
#include "Matrix4f.h"
#include "ReferenceManager.h"
#include "ClientHandle.h"
@ -134,8 +133,11 @@ void cEntity::WrapRotation()
void cEntity::MoveToCorrectChunk(bool a_bIgnoreOldChunk)
{
ASSERT(m_World != NULL); // Entity needs a world to move to a chunk
if (!m_World) return;
if (!m_World)
{
// This is normal for entities being currently loaded
return;
}
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
cWorld::BlockToChunk((int)m_Pos.x, (int)m_Pos.y, (int)m_Pos.z, ChunkX, ChunkY, ChunkZ);
@ -299,7 +301,7 @@ void cEntity::SetRot(const Vector3f & a_Rot)
void cEntity::SetRotation(float a_Rotation)
void cEntity::SetRotation(double a_Rotation)
{
m_Rot.x = a_Rotation;
m_bDirtyOrientation = true;
@ -309,7 +311,7 @@ void cEntity::SetRotation(float a_Rotation)
void cEntity::SetPitch(float a_Pitch)
void cEntity::SetPitch(double a_Pitch)
{
m_Rot.y = a_Pitch;
m_bDirtyOrientation = true;
@ -319,7 +321,7 @@ void cEntity::SetPitch(float a_Pitch)
void cEntity::SetRoll(float a_Roll)
void cEntity::SetRoll(double a_Roll)
{
m_Rot.z = a_Roll;
m_bDirtyOrientation = true;
@ -329,6 +331,15 @@ void cEntity::SetRoll(float a_Roll)
void cEntity::SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ)
{
m_Speed.Set(a_SpeedX, a_SpeedY, a_SpeedZ);
}
void cEntity::AddSpeed(const Vector3d & a_AddSpeed)
{
m_Speed += a_AddSpeed;
@ -340,11 +351,11 @@ void cEntity::AddSpeed(const Vector3d & a_AddSpeed)
//////////////////////////////////////////////////////////////////////////
// Get look vector (this is NOT a rotation!)
Vector3f cEntity::GetLookVector(void) const
Vector3d cEntity::GetLookVector(void) const
{
Matrix4f m;
Matrix4d m;
m.Init(Vector3f(), 0, m_Rot.x, -m_Rot.y);
Vector3f Look = m.Transform(Vector3f(0, 0, 1));
Vector3d Look = m.Transform(Vector3d(0, 0, 1));
return Look;
}

View File

@ -63,11 +63,12 @@ public:
etEntity, // For all other types
etPlayer,
etPickup,
etMob,
etMonster,
etMob = etMonster, // DEPRECATED, use etMonster instead!
etFallingBlock,
etMinecart,
// Older constants, left over for compatibility reasons (plugins)
// DEPRECATED older constants, left over for compatibility reasons (plugins)
eEntityType_Entity = etEntity,
eEntityType_Player = etPlayer,
eEntityType_Pickup = etPickup,
@ -108,11 +109,11 @@ public:
double GetPosX (void) const {return m_Pos.x; }
double GetPosY (void) const {return m_Pos.y; }
double GetPosZ (void) const {return m_Pos.z; }
const Vector3f & GetRot (void) const {return m_Rot; }
float GetRotation (void) const {return m_Rot.x; }
float GetPitch (void) const {return m_Rot.y; }
float GetRoll (void) const {return m_Rot.z; }
Vector3f GetLookVector(void) const;
const Vector3d & GetRot (void) const {return m_Rot; }
double GetRotation (void) const {return m_Rot.x; }
double GetPitch (void) const {return m_Rot.y; }
double GetRoll (void) const {return m_Rot.z; }
Vector3d GetLookVector(void) const;
const Vector3d & GetSpeed (void) const { return m_Speed; }
double GetSpeedX (void) const { return m_Speed.x; }
double GetSpeedY (void) const { return m_Speed.y; }
@ -128,11 +129,14 @@ public:
void SetPosition(double a_PosX, double a_PosY, double a_PosZ);
void SetPosition(const Vector3d & a_Pos);
void SetRot (const Vector3f & a_Rot);
void SetRotation(float a_Rotation);
void SetPitch (float a_Pitch);
void SetRoll (float a_Roll);
void SetRotation(double a_Rotation);
void SetPitch (double a_Pitch);
void SetRoll (double a_Roll);
void SetSpeed (double a_SpeedX, double a_SpeedY, double a_SpeedZ);
void SetSpeed (const Vector3d & a_Speed) { m_Speed = a_Speed; }
void AddSpeed(const Vector3d & a_AddSpeed);
// tolua_end
inline int GetUniqueID(void) const { return m_UniqueID; } // tolua_export
@ -173,16 +177,6 @@ public:
virtual void OnRightClicked(cPlayer & a_Player) {};
protected:
virtual void Destroyed(void) {} // Called after the entity has been destroyed
void SetWorld(cWorld * a_World) { m_World = a_World; }
void MoveToCorrectChunk(bool a_bIgnoreOldChunk = false);
friend class cReferenceManager;
void AddReference( cEntity*& a_EntityPtr );
void ReferencedBy( cEntity*& a_EntityPtr );
void Dereference( cEntity*& a_EntityPtr );
static cCriticalSection m_CSCount;
static int m_EntityCount;
@ -201,7 +195,7 @@ protected:
Vector3d m_Pos;
bool m_bDirtyPosition;
Vector3f m_Rot;
Vector3d m_Rot;
bool m_bDirtyOrientation;
Vector3d m_Speed;
@ -211,11 +205,21 @@ protected:
eEntityType m_EntityType;
cWorld* m_World;
cWorld * m_World;
float m_FireDamageInterval;
float m_BurnPeriod;
}; // tolua_export
virtual void Destroyed(void) {} // Called after the entity has been destroyed
void SetWorld(cWorld * a_World) { m_World = a_World; }
void MoveToCorrectChunk(bool a_bIgnoreOldChunk = false);
friend class cReferenceManager;
void AddReference( cEntity*& a_EntityPtr );
void ReferencedBy( cEntity*& a_EntityPtr );
void Dereference( cEntity*& a_EntityPtr );
} ; // tolua_export
typedef std::list<cEntity *> cEntityList;

View File

@ -109,3 +109,117 @@ public:
}
float cell[16];
};
class Matrix4d
{
public:
enum
{
TX=3,
TY=7,
TZ=11,
D0=0, D1=5, D2=10, D3=15,
SX=D0, SY=D1, SZ=D2,
W=D3
};
Matrix4d() { Identity(); }
double& operator [] ( int a_N ) { return cell[a_N]; }
void Identity()
{
cell[1] = cell[2] = cell[TX] = cell[4] = cell[6] = cell[TY] =
cell[8] = cell[9] = cell[TZ] = cell[12] = cell[13] = cell[14] = 0;
cell[D0] = cell[D1] = cell[D2] = cell[W] = 1;
}
void Init( Vector3f a_Pos, double a_RX, double a_RY, double a_RZ )
{
Matrix4d t;
t.RotateX( a_RZ );
RotateY( a_RY );
Concatenate( t );
t.RotateZ( a_RX );
Concatenate( t );
Translate( a_Pos );
}
void RotateX( double a_RX )
{
double sx = (double)sin( a_RX * M_PI / 180 );
double cx = (double)cos( a_RX * M_PI / 180 );
Identity();
cell[5] = cx, cell[6] = sx, cell[9] = -sx, cell[10] = cx;
}
void RotateY( double a_RY )
{
double sy = (double)sin( a_RY * M_PI / 180 );
double cy = (double)cos( a_RY * M_PI / 180 );
Identity ();
cell[0] = cy, cell[2] = -sy, cell[8] = sy, cell[10] = cy;
}
void RotateZ( double a_RZ )
{
double sz = (double)sin( a_RZ * M_PI / 180 );
double cz = (double)cos( a_RZ * M_PI / 180 );
Identity ();
cell[0] = cz, cell[1] = sz, cell[4] = -sz, cell[5] = cz;
}
void Translate( Vector3d a_Pos ) { cell[TX] += a_Pos.x; cell[TY] += a_Pos.y; cell[TZ] += a_Pos.z; }
void SetTranslation( Vector3d a_Pos ) { cell[TX] = a_Pos.x; cell[TY] = a_Pos.y; cell[TZ] = a_Pos.z; }
void Concatenate( const Matrix4d & m2 )
{
Matrix4d res;
int c;
for ( c = 0; c < 4; c++ ) for ( int r = 0; r < 4; r++ )
res.cell[r * 4 + c] = cell[r * 4] * m2.cell[c] +
cell[r * 4 + 1] * m2.cell[c + 4] +
cell[r * 4 + 2] * m2.cell[c + 8] +
cell[r * 4 + 3] * m2.cell[c + 12];
for ( c = 0; c < 16; c++ ) cell[c] = res.cell[c];
}
Vector3d Transform( const Vector3d & v ) const
{
double x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
double y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
double z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
return Vector3d( x, y, z );
}
void Invert()
{
Matrix4d t;
int h, i;
double tx = -cell[3], ty = -cell[7], tz = -cell[11];
for ( h = 0; h < 3; h++ ) for ( int v = 0; v < 3; v++ ) t.cell[h + v * 4] = cell[v + h * 4];
for ( i = 0; i < 11; i++ ) cell[i] = t.cell[i];
cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
}
Vector3d GetXColumn() { return Vector3d( cell[0], cell[1], cell[2] ); }
Vector3d GetYColumn() { return Vector3d( cell[4], cell[5], cell[6] ); }
Vector3d GetZColumn() { return Vector3d( cell[8], cell[9], cell[10] ); }
void SetXColumn( const Vector3d & a_X )
{
cell[0] = a_X.x;
cell[1] = a_X.y;
cell[2] = a_X.z;
}
void SetYColumn( const Vector3d & a_Y )
{
cell[4] = a_Y.x;
cell[5] = a_Y.y;
cell[6] = a_Y.z;
}
void SetZColumn( const Vector3d & a_Z )
{
cell[8] = a_Z.x;
cell[9] = a_Z.y;
cell[10] = a_Z.z;
}
double cell[16];
} ;

View File

@ -115,6 +115,17 @@ cMinecartWithChest::cMinecartWithChest(double a_X, double a_Y, double a_Z) :
void cMinecartWithChest::SetItem(int a_Idx, const cItem & a_Item)
{
ASSERT((a_Idx >= 0) && (a_Idx < ARRAYCOUNT(m_Items)));
m_Items[a_Idx] = a_Item;
}
void cMinecartWithChest::OnRightClicked(cPlayer & a_Player)
{
// Show the chest UI window to the player

View File

@ -10,6 +10,7 @@
#pragma once
#include "Entity.h"
#include "Item.h"
@ -74,8 +75,21 @@ class cMinecartWithChest :
public:
CLASS_PROTODEF(cMinecartWithChest);
/// Number of item slots in the chest
static const int NumSlots = 9 * 3;
cMinecartWithChest(double a_X, double a_Y, double a_Z);
const cItem & GetItem(int a_Idx) const { return m_Items[a_Idx]; }
cItem & GetItem(int a_Idx) { return m_Items[a_Idx]; }
void SetItem(int a_Idx, const cItem & a_Item);
protected:
/// The chest contents:
cItem m_Items[NumSlots];
// cEntity overrides:
virtual void OnRightClicked(cPlayer & a_Player) override;
} ;

View File

@ -145,10 +145,10 @@ void cMonster::Tick(float a_Dt, MTRand & a_TickRandom)
ReplicateMovement();
Vector3f Distance = m_Destination - Vector3f( m_Pos );
Vector3d Distance = m_Destination - Vector3f( m_Pos );
if (Distance.SqrLength() > 0.1f)
{
float Rotation, Pitch;
double Rotation, Pitch;
Distance.Normalize();
VectorToEuler( Distance.x, Distance.y, Distance.z, Rotation, Pitch );
SetRotation( Rotation );

View File

@ -26,6 +26,7 @@
cPickup::cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem & a_Item, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */)
: cEntity(etPickup, ((double)(a_MicroPosX)) / 32, ((double)(a_MicroPosY)) / 32, ((double)(a_MicroPosZ)) / 32)
, m_Health(5)
, m_bOnGround( false )
, m_bReplicated( false )
, m_Timer( 0.f )

View File

@ -38,7 +38,13 @@ public:
virtual void Tick(float a_Dt, MTRand & a_TickRandom) override;
virtual void HandlePhysics(float a_Dt) override;
short GetHealth(void) const { return m_Health; }
/// Returns the number of ticks that this entity has existed
short GetAge(void) const { return (short)(m_Timer / 50); }
private:
short m_Health;
Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)

View File

@ -5,7 +5,7 @@
// fwd: "cWorld.h"
// fwd: World.h
class cWorld;
@ -16,15 +16,15 @@ class cPiston
{
public:
cPiston( cWorld* a_World );
cPiston(cWorld * a_World);
static NIBBLETYPE RotationPitchToMetaData(float a_Rotation, float a_Pitch)
static NIBBLETYPE RotationPitchToMetaData(double a_Rotation, double a_Pitch)
{
if (a_Pitch >= 50.f)
if (a_Pitch >= 50)
{
return 0x1;
}
else if (a_Pitch <= -50.f)
else if (a_Pitch <= -50)
{
return 0x0;
}
@ -32,11 +32,11 @@ public:
{
a_Rotation += 90 + 45; // So its not aligned with axis
if (a_Rotation > 360.f)
if (a_Rotation > 360)
{
a_Rotation -= 360.f;
a_Rotation -= 360;
}
if ((a_Rotation >= 0.f) && (a_Rotation < 90.f))
if ((a_Rotation >= 0) && (a_Rotation < 90))
{
return 0x4;
}
@ -58,13 +58,12 @@ public:
void ExtendPiston( int, int, int );
void RetractPiston( int, int, int );
cWorld* m_World;
cWorld * m_World;
private:
void ChainMove( int, int, int, char, unsigned short * );
unsigned short FirstPassthroughBlock( int, int, int, char );
};
} ;

View File

@ -843,7 +843,7 @@ void cPlayer::TossItem(
}
}
}
float vX = 0, vY = 0, vZ = 0;
double vX = 0, vY = 0, vZ = 0;
EulerToVector(-GetRotation(), GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY() + 1.6f, GetPosZ(), vX * 2, vY * 2, vZ * 2);

View File

@ -556,8 +556,8 @@ void cProtocol125::SendPlayerMoveLook(void)
WriteDouble(Player->GetStance() + 0.03); // Add a small amount so that the player doesn't start inside a block
WriteDouble(Player->GetPosY() + 0.03); // Add a small amount so that the player doesn't start inside a block
WriteDouble(Player->GetPosZ());
WriteFloat (Player->GetRotation());
WriteFloat (Player->GetPitch());
WriteFloat ((float)(Player->GetRotation()));
WriteFloat ((float)(Player->GetPitch()));
WriteBool (Player->IsOnGround());
Flush();
}

View File

@ -1,32 +1,44 @@
#pragma once
class cSign // tolua_export
{ // tolua_export
// tolua_begin
class cSign
{
public:
static char RotationToMetaData( float a_Rotation ) // tolua_export
{ // tolua_export
a_Rotation += 180 + (180/16); // So its not aligned with axis
if( a_Rotation > 360.f ) a_Rotation -= 360.f;
static char RotationToMetaData(double a_Rotation)
{
a_Rotation += 180 + (180 / 16); // So it's not aligned with axis
if (a_Rotation > 360)
{
a_Rotation -= 360;
}
a_Rotation = (a_Rotation/360) * 16;
a_Rotation = (a_Rotation / 360) * 16;
return ((char)a_Rotation) % 16;
} // tolua_export
static char DirectionToMetaData( char a_Direction ) // tolua_export
{ // tolua_export
switch( a_Direction )
}
static char DirectionToMetaData(char a_Direction)
{
switch (a_Direction)
{
case 0x2:
return 0x2;
case 0x3:
return 0x3;
case 0x4:
return 0x4;
case 0x5:
return 0x5;
default:
break;
case 0x2: return 0x2;
case 0x3: return 0x3;
case 0x4: return 0x4;
case 0x5: return 0x5;
default:
break;
};
return 0x2;
}
}; // tolua_export
} ;
// tolua_end

View File

@ -1015,15 +1015,15 @@ bool cRedstoneSimulator::IsRepeaterPointingAway(const Vector3i & a_RepeaterPos,
NIBBLETYPE cRedstoneSimulator::RepeaterRotationToMetaData(float a_Rotation)
NIBBLETYPE cRedstoneSimulator::RepeaterRotationToMetaData(double a_Rotation)
{
a_Rotation += 90 + 45; // So its not aligned with axis
if (a_Rotation > 360.f)
if (a_Rotation > 360)
{
a_Rotation -= 360.f;
a_Rotation -= 360;
}
if ((a_Rotation >= 0.f) && (a_Rotation < 90.f))
if ((a_Rotation >= 0) && (a_Rotation < 90))
{
return 0x1;
}

View File

@ -33,7 +33,7 @@ public:
static bool IsRepeaterPointingTo (const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos);
static bool IsRepeaterPointingAway(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos);
static NIBBLETYPE RepeaterRotationToMetaData(float a_Rotation);
static NIBBLETYPE RepeaterRotationToMetaData(double a_Rotation);
static Vector3i GetRepeaterDirection(NIBBLETYPE a_MetaData);
static NIBBLETYPE LeverDirectionToMetaData(char a_Dir);
static bool IsLeverOn(cWorld * a_World, const Vector3i & a_BlockPos);

View File

@ -5,19 +5,21 @@
class cStairs // tolua_export
{ // tolua_export
// tolua_begin
class cStairs
{
public:
/// Converts player rotation to stair rotation metadata. To get upside-down stairs, OR with 0x4
static NIBBLETYPE RotationToMetaData(float a_Rotation) // tolua_export
{ // tolua_export
a_Rotation += 90 + 45; // So its not aligned with axis
NIBBLETYPE result = 0x0;
if (a_Rotation > 360.f)
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
a_Rotation += 90 + 45; // So its not aligned with axis
NIBBLETYPE result = 0x0;
if (a_Rotation > 360)
{
a_Rotation -= 360.f;
a_Rotation -= 360;
}
if ((a_Rotation >= 0.f) && (a_Rotation < 90.f))
if ((a_Rotation >= 0) && (a_Rotation < 90))
{
return 0x0;
}
@ -33,9 +35,10 @@ public:
{
return 0x3;
}
} // tolua_export
} ; // tolua_export
}
} ;
// tolua_end

View File

@ -764,7 +764,7 @@ void cSlotAreaTemporary::TossItems(cPlayer & a_Player, int a_Begin, int a_End)
Item.Empty();
} // for i - itr->second[]
float vX = 0, vY = 0, vZ = 0;
double vX = 0, vY = 0, vZ = 0;
EulerToVector(-a_Player.GetRotation(), a_Player.GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
a_Player.GetWorld()->SpawnItemPickups(Drops, a_Player.GetPosX(), a_Player.GetPosY() + 1.6f, a_Player.GetPosZ(), vX * 2, vY * 2, vZ * 2);

View File

@ -385,9 +385,10 @@ void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType)
m_Result.append(4, (char)0);
++m_CurrentStack;
m_Stack[m_CurrentStack].m_Type = TAG_List;
m_Stack[m_CurrentStack].m_Pos = m_Result.size() - 4;
m_Stack[m_CurrentStack].m_Count = 0;
m_Stack[m_CurrentStack].m_Type = TAG_List;
m_Stack[m_CurrentStack].m_Pos = m_Result.size() - 4;
m_Stack[m_CurrentStack].m_Count = 0;
m_Stack[m_CurrentStack].m_ItemType = a_ChildrenType;
}

View File

@ -247,6 +247,7 @@ protected:
int m_Type; // TAG_Compound or TAG_List
int m_Pos; // for TAG_List, the position of the list count
int m_Count; // for TAG_List, the element count
eTagType m_ItemType; // for TAG_List, the element type
} ;
static const int MAX_STACK = 50; // Highliy doubtful that an NBT would be constructed this many levels deep
@ -263,6 +264,9 @@ protected:
inline void TagCommon(const AString & a_Name, eTagType a_Type)
{
// If we're directly inside a list, check that the list is of the correct type:
ASSERT((m_Stack[m_CurrentStack].m_Type != TAG_List) || (m_Stack[m_CurrentStack].m_ItemType == a_Type));
if (IsStackTopCompound())
{
// Compound: add the type and name:

View File

@ -0,0 +1,417 @@
// NBTChunkSerializer.cpp
#include "Globals.h"
#include "NBTChunkSerializer.h"
#include "../BlockID.h"
#include "../ChestEntity.h"
#include "../DispenserEntity.h"
#include "../FurnaceEntity.h"
#include "../SignEntity.h"
#include "../NoteEntity.h"
#include "../JukeboxEntity.h"
#include "../Item.h"
#include "../StringCompression.h"
#include "../Entity.h"
#include "../OSSupport/MakeDir.h"
#include "FastNBT.h"
#include "../FallingBlock.h"
#include "../Minecart.h"
#include "../Mobs/Monster.h"
#include "../Pickup.h"
cNBTChunkSerializer::cNBTChunkSerializer(cFastNBTWriter & a_Writer) :
m_BiomesAreValid(false),
m_Writer(a_Writer),
m_IsTagOpen(false),
m_HasHadEntity(false),
m_HasHadBlockEntity(false),
m_IsLightValid(false)
{
}
void cNBTChunkSerializer::Finish(void)
{
if (m_IsTagOpen)
{
m_Writer.EndList();
}
// If light not valid, reset it to all zeroes:
if (!m_IsLightValid)
{
memset(m_BlockLight, 0, sizeof(m_BlockLight));
memset(m_BlockSkyLight, 0, sizeof(m_BlockSkyLight));
}
}
void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AString & a_CompoundName)
{
m_Writer.BeginCompound(a_CompoundName);
m_Writer.AddShort("id", (short)(a_Item.m_ItemType));
m_Writer.AddShort("Damage", a_Item.m_ItemDamage);
m_Writer.AddByte ("Count", a_Item.m_ItemCount);
if (a_Slot >= 0)
{
m_Writer.AddByte ("Slot", (unsigned char)a_Slot);
}
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID)
{
m_Writer.AddInt ("x", a_Entity->GetPosX());
m_Writer.AddInt ("y", a_Entity->GetPosY());
m_Writer.AddInt ("z", a_Entity->GetPosZ());
m_Writer.AddString("id", a_EntityTypeID);
}
void cNBTChunkSerializer::AddChestEntity(cChestEntity * a_Entity)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Entity, "Chest");
m_Writer.BeginList("Items", TAG_Compound);
for (int i = 0; i < cChestEntity::c_ChestHeight * cChestEntity::c_ChestWidth; i++)
{
const cItem * Item = a_Entity->GetSlot(i);
if ((Item == NULL) || Item->IsEmpty())
{
continue;
}
AddItem(*Item, i);
} // for i - chest slots[]
m_Writer.EndList();
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddDispenserEntity(cDispenserEntity * a_Entity)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Entity, "Trap");
m_Writer.BeginList("Items", TAG_Compound);
for (int i = 0; i < 9; i++)
{
const cItem * Item = a_Entity->GetSlot(i);
if ((Item == NULL) || Item->IsEmpty())
{
continue;
}
AddItem(*Item, i);
} // for i - contents[]
m_Writer.EndList();
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddFurnaceEntity(cFurnaceEntity * a_Furnace)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Furnace, "Furnace");
m_Writer.BeginList("Items", TAG_Compound);
AddItem(*(a_Furnace->GetSlot(0)), 0);
AddItem(*(a_Furnace->GetSlot(1)), 1);
AddItem(*(a_Furnace->GetSlot(2)), 2);
m_Writer.EndList();
m_Writer.AddShort("BurnTime", (Int16)(a_Furnace->GetTimeToBurn() / 50.0));
m_Writer.AddShort("CookTime", (Int16)(a_Furnace->GetTimeCooked() / 50.0));
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddSignEntity(cSignEntity * a_Sign)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Sign, "Sign");
m_Writer.AddString("Text1", a_Sign->GetLine(0));
m_Writer.AddString("Text2", a_Sign->GetLine(1));
m_Writer.AddString("Text3", a_Sign->GetLine(2));
m_Writer.AddString("Text4", a_Sign->GetLine(3));
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Note, "Music");
m_Writer.AddByte("note", a_Note->GetPitch());
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddJukeboxEntity(cJukeboxEntity * a_Jukebox)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Jukebox, "RecordPlayer");
m_Writer.AddInt("Record", a_Jukebox->GetRecord());
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_ClassName)
{
m_Writer.AddString("id", a_ClassName);
m_Writer.BeginList("Pos", TAG_Double);
m_Writer.AddDouble("", a_Entity->GetPosX());
m_Writer.AddDouble("", a_Entity->GetPosY());
m_Writer.AddDouble("", a_Entity->GetPosZ());
m_Writer.EndList();
m_Writer.BeginList("Motion", TAG_Double);
m_Writer.AddDouble("", a_Entity->GetSpeedX());
m_Writer.AddDouble("", a_Entity->GetSpeedY());
m_Writer.AddDouble("", a_Entity->GetSpeedZ());
m_Writer.EndList();
m_Writer.BeginList("Rotation", TAG_Double);
m_Writer.AddDouble("", a_Entity->GetRotation());
m_Writer.AddDouble("", a_Entity->GetPitch());
m_Writer.EndList();
}
void cNBTChunkSerializer::AddFallingBlockEntity(cFallingBlock * a_FallingBlock)
{
m_Writer.BeginCompound("");
AddBasicEntity(a_FallingBlock, "FallingSand");
m_Writer.AddInt("TileID", a_FallingBlock->GetBlockType());
m_Writer.AddByte("Data", a_FallingBlock->GetBlockMeta());
m_Writer.AddByte("Time", 1); // Unused in MCServer, Vanilla said to need nonzero
m_Writer.AddByte("DropItem", 1);
m_Writer.AddByte("HurtEntities", a_FallingBlock->GetBlockType() == E_BLOCK_ANVIL);
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddMinecartEntity(cMinecart * a_Minecart)
{
const char * EntityClass = NULL;
switch (a_Minecart->GetPayload())
{
case cMinecart::mpNone: EntityClass = "MinecarRideable"; break;
case cMinecart::mpChest: EntityClass = "MinecartChest"; break;
case cMinecart::mpFurnace: EntityClass = "MinecartFurnace"; break;
default:
{
ASSERT(!"Unhandled minecart payload type");
return;
}
} // switch (payload)
m_Writer.BeginCompound("");
AddBasicEntity(a_Minecart, EntityClass);
switch (a_Minecart->GetPayload())
{
case cMinecart::mpChest:
{
// Add chest contents into the Items tag:
AddMinecartChestContents((cMinecartWithChest *)a_Minecart);
break;
}
case cMinecart::mpFurnace:
{
// TODO: Add "Push" and "Fuel" tags
break;
}
} // switch (Payload)
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
{
// TODO
}
void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup)
{
m_Writer.BeginCompound("");
AddBasicEntity(a_Pickup, "Item");
AddItem(a_Pickup->GetItem(), -1, "Item");
m_Writer.AddShort("Health", a_Pickup->GetHealth());
m_Writer.AddShort("Age", a_Pickup->GetAge());
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{
m_Writer.BeginList("Items", TAG_Compound);
for (int i = 0; i < cMinecartWithChest::NumSlots; i++)
{
const cItem & Item = a_Minecart->GetItem(i);
if (Item.IsEmpty())
{
continue;
}
AddItem(Item, i);
}
m_Writer.EndList();
}
bool cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
{
m_IsLightValid = a_IsLightValid;
return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother
}
void cNBTChunkSerializer::BiomeData(const cChunkDef::BiomeMap * a_BiomeMap)
{
memcpy(m_Biomes, a_BiomeMap, sizeof(m_Biomes));
for (int i = 0; i < ARRAYCOUNT(m_Biomes); i++)
{
if ((*a_BiomeMap)[i] < 255)
{
// Normal MC biome, copy as-is:
m_VanillaBiomes[i] = (unsigned char)((*a_BiomeMap)[i]);
}
else
{
// TODO: MCS-specific biome, need to map to some basic MC biome:
ASSERT(!"Unimplemented MCS-specific biome");
return;
}
} // for i - m_BiomeMap[]
m_BiomesAreValid = true;
}
void cNBTChunkSerializer::Entity(cEntity * a_Entity)
{
// Add entity into NBT:
if (m_IsTagOpen)
{
if (!m_HasHadEntity)
{
m_Writer.EndList();
m_Writer.BeginList("Entities", TAG_Compound);
}
}
else
{
m_Writer.BeginList("Entities", TAG_Compound);
}
m_IsTagOpen = true;
m_HasHadEntity = true;
switch (a_Entity->GetEntityType())
{
case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *)a_Entity); break;
case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break;
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
case cEntity::etPlayer: return; // Players aren't saved into the world
default:
{
ASSERT(!"Unhandled entity type is being saved");
break;
}
}
}
void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
{
if (m_IsTagOpen)
{
if (!m_HasHadBlockEntity)
{
m_Writer.EndList();
m_Writer.BeginList("TileEntities", TAG_Compound);
}
}
else
{
m_Writer.BeginList("TileEntities", TAG_Compound);
}
m_IsTagOpen = true;
// Add tile-entity into NBT:
switch (a_Entity->GetBlockType())
{
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break;
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
default:
{
ASSERT(!"Unhandled block entity saved into Anvil");
}
}
m_HasHadBlockEntity = true;
}

View File

@ -0,0 +1,101 @@
// NBTChunkSerializer.h
// Declares the cNBTChunkSerializer class that is used for saving individual chunks into NBT format used by Anvil
#pragma once
#include "../ChunkDef.h"
// fwd:
class cFastNBTWriter;
class cEntity;
class cBlockEntity;
class cChestEntity;
class cFurnaceEntity;
class cDispenserEntity;
class cSignEntity;
class cNoteEntity;
class cJukeboxEntity;
class cFallingBlock;
class cMinecart;
class cMinecartWithChest;
class cMinecartWithFurnace;
class cMonster;
class cPickup;
class cNBTChunkSerializer :
public cChunkDataSeparateCollector
{
public:
cChunkDef::BiomeMap m_Biomes;
unsigned char m_VanillaBiomes[cChunkDef::Width * cChunkDef::Width];
bool m_BiomesAreValid;
cNBTChunkSerializer(cFastNBTWriter & a_Writer);
/// Close NBT tags that we've opened
void Finish(void);
bool IsLightValid(void) const {return m_IsLightValid; }
protected:
/* From cChunkDataSeparateCollector we inherit:
- m_BlockTypes[]
- m_BlockMetas[]
- m_BlockLight[]
- m_BlockSkyLight[]
*/
cFastNBTWriter & m_Writer;
bool m_IsTagOpen; // True if a tag has been opened in the callbacks and not yet closed.
bool m_HasHadEntity; // True if any Entity has already been received and processed
bool m_HasHadBlockEntity; // True if any BlockEntity has already been received and processed
bool m_IsLightValid; // True if the chunk lighting is valid
/// Writes an item into the writer, if slot >= 0, adds the Slot tag. The compound is named as requested.
void AddItem(const cItem & a_Item, int a_Slot, const AString & a_CompoundName = "");
// Block entities:
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID);
void AddChestEntity(cChestEntity * a_Entity);
void AddDispenserEntity(cDispenserEntity * a_Entity);
void AddFurnaceEntity(cFurnaceEntity * a_Furnace);
void AddSignEntity(cSignEntity * a_Sign);
void AddNoteEntity(cNoteEntity * a_Note);
void AddJukeboxEntity(cJukeboxEntity * a_Jukebox);
void AddBasicEntity(cEntity * a_Entity, const AString & a_ClassName);
// Entities:
void AddFallingBlockEntity(cFallingBlock * a_FallingBlock);
void AddMinecartEntity (cMinecart * a_Minecart);
void AddMonsterEntity (cMonster * a_Monster);
void AddPickupEntity (cPickup * a_Pickup);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
// cChunkDataSeparateCollector overrides:
virtual bool LightIsValid(bool a_IsLightValid) override;
virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override;
virtual void Entity(cEntity * a_Entity) override;
virtual void BlockEntity(cBlockEntity * a_Entity) override;
} ; // class cNBTChunkSerializer

View File

@ -5,6 +5,7 @@
#include "Globals.h"
#include "WSSAnvil.h"
#include "NBTChunkSerializer.h"
#include "../World.h"
#include "zlib.h"
#include "../BlockID.h"
@ -19,6 +20,10 @@
#include "../Entity.h"
#include "../OSSupport/MakeDir.h"
#include "FastNBT.h"
#include "../FallingBlock.h"
#include "../Minecart.h"
#include "../Mobs/Monster.h"
#include "../Pickup.h"
@ -37,238 +42,6 @@ Since only the header is actually in the memory, this number can be high, but st
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cNBTChunkSerializer
class cNBTChunkSerializer :
public cChunkDataSeparateCollector
{
public:
cChunkDef::BiomeMap m_Biomes;
unsigned char m_VanillaBiomes[cChunkDef::Width * cChunkDef::Width];
bool m_BiomesAreValid;
cNBTChunkSerializer(cFastNBTWriter & a_Writer) :
m_BiomesAreValid(false),
m_Writer(a_Writer),
m_IsTagOpen(false),
m_HasHadEntity(false),
m_HasHadBlockEntity(false),
m_IsLightValid(false)
{
}
/// Close NBT tags that we've opened
void Finish(void)
{
if (m_IsTagOpen)
{
m_Writer.EndList();
}
// If light not valid, reset it to all zeroes:
if (!m_IsLightValid)
{
memset(m_BlockLight, 0, sizeof(m_BlockLight));
memset(m_BlockSkyLight, 0, sizeof(m_BlockSkyLight));
}
}
bool IsLightValid(void) const {return m_IsLightValid; }
protected:
/* From cChunkDataSeparateCollector we inherit:
- m_BlockTypes[]
- m_BlockMetas[]
- m_BlockLight[]
- m_BlockSkyLight[]
*/
cFastNBTWriter & m_Writer;
bool m_IsTagOpen; // True if a tag has been opened in the callbacks and not yet closed.
bool m_HasHadEntity; // True if any Entity has already been received and processed
bool m_HasHadBlockEntity; // True if any BlockEntity has already been received and processed
bool m_IsLightValid; // True if the chunk lighting is valid
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID)
{
m_Writer.AddInt ("x", a_Entity->GetPosX());
m_Writer.AddInt ("y", a_Entity->GetPosY());
m_Writer.AddInt ("z", a_Entity->GetPosZ());
m_Writer.AddString("id", a_EntityTypeID);
}
void AddItem(const cItem * a_Item, int a_Slot)
{
m_Writer.BeginCompound("");
m_Writer.AddShort("id", (short)(a_Item->m_ItemType));
m_Writer.AddShort("Damage", a_Item->m_ItemDamage);
m_Writer.AddByte ("Count", a_Item->m_ItemCount);
m_Writer.AddByte ("Slot", (unsigned char)a_Slot);
m_Writer.EndCompound();
}
void AddChestEntity(cChestEntity * a_Entity)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Entity, "Chest");
m_Writer.BeginList("Items", TAG_Compound);
for (int i = 0; i < cChestEntity::c_ChestHeight * cChestEntity::c_ChestWidth; i++)
{
const cItem * Item = a_Entity->GetSlot(i);
if ((Item == NULL) || Item->IsEmpty())
{
continue;
}
AddItem(Item, i);
}
m_Writer.EndList();
m_Writer.EndCompound();
}
void AddDispenserEntity(cDispenserEntity * a_Entity)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Entity, "Trap");
m_Writer.BeginList("Items", TAG_Compound);
for (int i = 0; i < 9; i++)
{
const cItem * Item = a_Entity->GetSlot(i);
if ((Item == NULL) || Item->IsEmpty())
{
continue;
}
AddItem(Item, i);
}
m_Writer.EndList();
m_Writer.EndCompound();
}
void AddFurnaceEntity(cFurnaceEntity * a_Furnace)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Furnace, "Furnace");
m_Writer.BeginList("Items", TAG_Compound);
AddItem(a_Furnace->GetSlot(0), 0);
AddItem(a_Furnace->GetSlot(1), 1);
AddItem(a_Furnace->GetSlot(2), 2);
m_Writer.EndList();
m_Writer.AddShort("BurnTime", (Int16)(a_Furnace->GetTimeToBurn() / 50.0));
m_Writer.AddShort("CookTime", (Int16)(a_Furnace->GetTimeCooked() / 50.0));
m_Writer.EndCompound();
}
void AddSignEntity(cSignEntity * a_Sign)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Sign, "Sign");
m_Writer.AddString("Text1", a_Sign->GetLine(0));
m_Writer.AddString("Text2", a_Sign->GetLine(1));
m_Writer.AddString("Text3", a_Sign->GetLine(2));
m_Writer.AddString("Text4", a_Sign->GetLine(3));
m_Writer.EndCompound();
}
void AddNoteEntity(cNoteEntity * a_Note)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Note, "Music");
m_Writer.AddByte("note", a_Note->GetPitch());
m_Writer.EndCompound();
}
void AddJukeboxEntity(cJukeboxEntity * a_Jukebox)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Jukebox, "RecordPlayer");
m_Writer.AddInt("Record", a_Jukebox->GetRecord());
m_Writer.EndCompound();
}
virtual bool LightIsValid(bool a_IsLightValid) override
{
m_IsLightValid = a_IsLightValid;
return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother
}
virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override
{
memcpy(m_Biomes, a_BiomeMap, sizeof(m_Biomes));
for (int i = 0; i < ARRAYCOUNT(m_Biomes); i++)
{
if ((*a_BiomeMap)[i] < 255)
{
// Normal MC biome, copy as-is:
m_VanillaBiomes[i] = (unsigned char)((*a_BiomeMap)[i]);
}
else
{
// TODO: MCS-specific biome, need to map to some basic MC biome:
ASSERT(!"Unimplemented MCS-specific biome");
return;
}
} // for i - m_BiomeMap[]
m_BiomesAreValid = true;
}
virtual void Entity(cEntity * a_Entity) override
{
// TODO: Add entity into NBT:
}
virtual void BlockEntity(cBlockEntity * a_Entity)
{
if (m_IsTagOpen)
{
if (!m_HasHadBlockEntity)
{
m_Writer.EndList();
m_Writer.BeginList("TileEntities", TAG_Compound);
}
}
else
{
m_Writer.BeginList("TileEntities", TAG_Compound);
}
m_IsTagOpen = true;
// Add tile-entity into NBT:
switch (a_Entity->GetBlockType())
{
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break;
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
default:
{
ASSERT(!"Unhandled block entity saved into Anvil");
}
}
m_HasHadBlockEntity = true;
}
} ; // class cNBTChunkSerializer
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cWSSAnvil:
@ -378,6 +151,9 @@ bool cWSSAnvil::SetChunkData(const cChunkCoords & a_Chunk, const AString & a_Dat
{
return false;
}
LOGD("Saving chunk [%d, %d] into region file %s",
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, File->GetFileName().c_str()
);
return File->SetChunkData(a_Chunk, a_Data);
}
@ -392,6 +168,10 @@ cWSSAnvil::cMCAFile * cWSSAnvil::LoadMCAFile(const cChunkCoords & a_Chunk)
const int RegionX = FAST_FLOOR_DIV(a_Chunk.m_ChunkX, 32);
const int RegionZ = FAST_FLOOR_DIV(a_Chunk.m_ChunkZ, 32);
ASSERT(a_Chunk.m_ChunkX - RegionX * 32 >= 0);
ASSERT(a_Chunk.m_ChunkZ - RegionZ * 32 >= 0);
ASSERT(a_Chunk.m_ChunkX - RegionX * 32 < 32);
ASSERT(a_Chunk.m_ChunkZ - RegionZ * 32 < 32);
// Is it already cached?
for (cMCAFiles::iterator itr = m_Files.begin(); itr != m_Files.end(); ++itr)
@ -478,6 +258,7 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data)
return false;
}
Writer.Finish();
CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data);
return true;
}
@ -719,9 +500,26 @@ cChunkDef::BiomeMap * cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_Bio
void cWSSAnvil::LoadEntitiesFromNBT(cEntityList & a_Entitites, const cParsedNBT & a_NBT, int a_TagIdx)
void cWSSAnvil::LoadEntitiesFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
// TODO: Load the entities
if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List))
{
return;
}
for (int Child = a_NBT.GetFirstChild(a_TagIdx); Child != -1; Child = a_NBT.GetNextSibling(Child))
{
if (a_NBT.GetType(Child) != TAG_Compound)
{
continue;
}
int sID = a_NBT.FindChildByName(Child, "id");
if (sID < 0)
{
continue;
}
LoadEntityFromNBT(a_Entities, a_NBT, Child, a_NBT.GetData(sID), a_NBT.GetDataLength(sID));
} // for Child - a_NBT[]
}
@ -778,6 +576,37 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx)
{
int ID = a_NBT.FindChildByName(a_TagIdx, "id");
if ((ID < 0) || (a_NBT.GetType(ID) != TAG_Short))
{
return false;
}
a_Item.m_ItemType = (ENUM_ITEM_ID)(a_NBT.GetShort(ID));
int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage");
if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
{
return false;
}
a_Item.m_ItemDamage = a_NBT.GetShort(Damage);
int Count = a_NBT.FindChildByName(a_TagIdx, "Count");
if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte))
{
return false;
}
a_Item.m_ItemCount = a_NBT.GetByte(Count);
// TODO: enchantments and other item properties
return true;
}
void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
@ -800,25 +629,10 @@ void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cPars
continue;
}
cItem Item;
int ID = a_NBT.FindChildByName(Child, "id");
if ((ID < 0) || (a_NBT.GetType(ID) != TAG_Short))
if (LoadItemFromNBT(Item, a_NBT, Child))
{
continue;
Chest->SetSlot(a_NBT.GetByte(Slot), Item);
}
Item.m_ItemType = (ENUM_ITEM_ID)(a_NBT.GetShort(ID));
int Damage = a_NBT.FindChildByName(Child, "Damage");
if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
{
continue;
}
Item.m_ItemDamage = a_NBT.GetShort(Damage);
int Count = a_NBT.FindChildByName(Child, "Count");
if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte))
{
continue;
}
Item.m_ItemCount = a_NBT.GetByte(Count);
Chest->SetSlot(a_NBT.GetByte(Slot), Item);
} // for itr - ItemDefs[]
a_BlockEntities.push_back(Chest.release());
}
@ -849,25 +663,10 @@ void cWSSAnvil::LoadDispenserFromNBT(cBlockEntityList & a_BlockEntities, const c
continue;
}
cItem Item;
int ID = a_NBT.FindChildByName(Child, "id");
if ((ID < 0) || (a_NBT.GetType(ID) != TAG_Short))
if (LoadItemFromNBT(Item, a_NBT, Child))
{
continue;
Dispenser->SetSlot(a_NBT.GetByte(Slot), Item);
}
Item.m_ItemType = (ENUM_ITEM_ID)(a_NBT.GetShort(ID));
int Damage = a_NBT.FindChildByName(Child, "Damage");
if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
{
continue;
}
Item.m_ItemDamage = a_NBT.GetShort(Damage);
int Count = a_NBT.FindChildByName(Child, "Count");
if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte))
{
continue;
}
Item.m_ItemCount = a_NBT.GetByte(Count);
Dispenser->SetSlot(a_NBT.GetByte(Slot), Item);
} // for itr - ItemDefs[]
a_BlockEntities.push_back(Dispenser.release());
}
@ -898,25 +697,10 @@ void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cPa
continue;
}
cItem Item;
int ID = a_NBT.FindChildByName(Child, "id");
if ((ID < 0) || (a_NBT.GetType(ID) != TAG_Short))
if (LoadItemFromNBT(Item, a_NBT, Child))
{
continue;
Furnace->SetSlot(a_NBT.GetByte(Slot), Item);
}
Item.m_ItemType = (ENUM_ITEM_ID)(a_NBT.GetShort(ID));
int Damage = a_NBT.FindChildByName(Child, "Damage");
if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
{
continue;
}
Item.m_ItemDamage = a_NBT.GetShort(Damage);
int Count = a_NBT.FindChildByName(Child, "Count");
if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte))
{
continue;
}
Item.m_ItemCount = a_NBT.GetByte(Count);
Furnace->SetSlot(a_NBT.GetByte(Slot), Item);
} // for itr - ItemDefs[]
int BurnTime = a_NBT.FindChildByName(a_TagIdx, "BurnTime");
if (BurnTime >= 0)
@ -1022,6 +806,159 @@ void cWSSAnvil::LoadJukeboxFromNBT(cBlockEntityList & a_BlockEntities, const cPa
void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength)
{
if (strncmp(a_IDTag, "FallingBlock", a_IDTagLength) == 0)
{
LoadFallingBlockFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
else if (strncmp(a_IDTag, "Minecart", a_IDTagLength) == 0)
{
// It is a minecart, old style, find out the type:
int TypeTag = a_NBT.FindChildByName(a_EntityTagIdx, "Type");
if ((TypeTag < 0) || (a_NBT.GetType(TypeTag) != TAG_Int))
{
return;
}
switch (a_NBT.GetInt(TypeTag))
{
case 0: LoadMinecartRFromNBT(a_Entities, a_NBT, a_EntityTagIdx); break; // Rideable minecart
case 1: LoadMinecartCFromNBT(a_Entities, a_NBT, a_EntityTagIdx); break; // Minecart with chest
case 2: LoadMinecartFFromNBT(a_Entities, a_NBT, a_EntityTagIdx); break; // Minecart with furnace
}
}
else if (strncmp(a_IDTag, "MinecartRideable", a_IDTagLength) == 0)
{
LoadMinecartRFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
else if (strncmp(a_IDTag, "MinecartChest", a_IDTagLength) == 0)
{
LoadMinecartCFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
else if (strncmp(a_IDTag, "MinecartFurnace", a_IDTagLength) == 0)
{
LoadMinecartFFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
if (strncmp(a_IDTag, "Item", a_IDTagLength) == 0)
{
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
// TODO: other entities
}
void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
// TODO
}
void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
// TODO
}
void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
// TODO
}
void cWSSAnvil::LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
// TODO
}
void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
{
return;
}
cItem Item;
if (!LoadItemFromNBT(Item, a_NBT, ItemTag))
{
return;
}
std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item));
if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx))
{
return;
}
a_Entities.push_back(Pickup.release());
}
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
{
double Pos[3];
if (!LoadDoublesListFromNBT(Pos, 3, a_NBT, a_NBT.FindChildByName(a_TagIdx, "Pos")))
{
return false;
}
a_Entity.SetPosition(Pos[0], Pos[1], Pos[2]);
double Speed[3];
if (!LoadDoublesListFromNBT(Speed, 3, a_NBT, a_NBT.FindChildByName(a_TagIdx, "Motion")))
{
return false;
}
a_Entity.SetSpeed(Speed[0], Speed[1], Speed[2]);
double Rotation[3];
if (!LoadDoublesListFromNBT(Rotation, 2, a_NBT, a_NBT.FindChildByName(a_TagIdx, "Rotation")))
{
return false;
}
a_Entity.SetRotation(Rotation[0]);
a_Entity.SetRoll (Rotation[1]);
return true;
}
bool cWSSAnvil::LoadDoublesListFromNBT(double * a_Doubles, int a_NumDoubles, const cParsedNBT & a_NBT, int a_TagIdx)
{
if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List) || (a_NBT.GetChildrenType(a_TagIdx) != TAG_Double))
{
return false;
}
int idx = 0;
for (int Tag = a_NBT.GetFirstChild(a_TagIdx); (Tag > 0) && (idx < a_NumDoubles); Tag = a_NBT.GetNextSibling(Tag), ++idx)
{
a_Doubles[idx] = a_NBT.GetDouble(Tag);
} // for Tag - PosTag[]
return (idx == a_NumDoubles); // Did we read enough doubles?
}
bool cWSSAnvil::GetBlockEntityNBTPos(const cParsedNBT & a_NBT, int a_TagIdx, int & a_X, int & a_Y, int & a_Z)
{
int x = a_NBT.FindChildByName(a_TagIdx, "x");
@ -1162,6 +1099,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
{
if (!OpenFile(false))
{
LOGWARNING("Cannot save chunk [%d, %d], opening file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
return false;
}
@ -1183,15 +1121,18 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
unsigned ChunkSize = htonl(a_Data.size() + 1);
if (m_File.Write(&ChunkSize, 4) != 4)
{
LOGWARNING("Cannot save chunk [%d, %d], writing(1) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
return false;
}
char CompressionType = 2;
if (m_File.Write(&CompressionType, 1) != 1)
{
LOGWARNING("Cannot save chunk [%d, %d], writing(2) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
return false;
}
if (m_File.Write(a_Data.data(), a_Data.size()) != (int)(a_Data.size()))
{
LOGWARNING("Cannot save chunk [%d, %d], writing(3) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
return false;
}
@ -1199,9 +1140,14 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
ChunkSize = (a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number
ASSERT(ChunkSize < 256);
m_Header[LocalX + 32 * LocalZ] = htonl((ChunkSector << 8) | ChunkSize);
m_File.Seek(0);
if (m_File.Seek(0) < 0)
{
LOGWARNING("Cannot save chunk [%d, %d], seeking in file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
return false;
}
if (m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header))
{
LOGWARNING("Cannot save chunk [%d, %d], writing header to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str());
return false;
}

View File

@ -111,6 +111,9 @@ protected:
/// Loads the chunk's BlockEntities from NBT data (a_Tag is the Level\\TileEntities list tag; may be -1)
void LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntitites, const cParsedNBT & a_NBT, int a_Tag);
/// Loads a cItem contents from the specified NBT tag; returns true if successful. Doesn't load the Slot tag
bool LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
@ -118,6 +121,20 @@ protected:
void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength);
void LoadFallingBlockFromNBT(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);
void LoadMinecartFFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
/// Loads entity common data from the NBT compound; returns true if successful
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);
/// Loads an array of doubles of the specified length from the specified NBT list tag a_TagIdx; returns true if successful
bool LoadDoublesListFromNBT(double * a_Doubles, int a_NumDoubles, const cParsedNBT & a_NBT, int a_TagIdx);
/// Helper function for extracting the X, Y, and Z int subtags of a NBT compound; returns true if successful
bool GetBlockEntityNBTPos(const cParsedNBT & a_NBT, int a_TagIdx, int & a_X, int & a_Y, int & a_Z);