summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/LuaState.cpp1
-rw-r--r--src/BlockEntities/DispenserEntity.cpp2
-rw-r--r--src/BlockInfo.cpp2
-rw-r--r--src/Blocks/BlockHandler.h2
-rw-r--r--src/Blocks/BlockStairs.h8
-rw-r--r--src/Blocks/BlockVine.h16
-rw-r--r--src/Blocks/MetaRotater.h21
-rw-r--r--src/ByteBuffer.cpp66
-rw-r--r--src/ByteBuffer.h30
-rw-r--r--src/ChunkDef.h17
-rw-r--r--src/ClientHandle.cpp110
-rw-r--r--src/ClientHandle.h8
-rw-r--r--src/CraftingRecipes.cpp87
-rw-r--r--src/CraftingRecipes.h3
-rw-r--r--src/Entities/Floater.h2
-rw-r--r--src/Entities/Minecart.cpp4
-rw-r--r--src/Entities/Minecart.h4
-rw-r--r--src/Entities/Player.cpp32
-rw-r--r--src/Entities/Player.h11
-rw-r--r--src/Entities/ProjectileEntity.cpp87
-rw-r--r--src/Entities/ProjectileEntity.h12
-rw-r--r--src/Entities/TNTEntity.cpp33
-rw-r--r--src/Entities/TNTEntity.h23
-rw-r--r--src/Generating/MineShafts.cpp2
-rw-r--r--src/Generating/Trees.cpp2
-rw-r--r--src/Item.cpp22
-rw-r--r--src/Item.h16
-rw-r--r--src/Items/ItemHandler.h3
-rw-r--r--src/Items/ItemLighter.h4
-rw-r--r--src/Items/ItemThrowable.h6
-rw-r--r--src/Mobs/Sheep.cpp26
-rw-r--r--src/OSSupport/SocketThreads.h2
-rw-r--r--src/Protocol/Protocol.h2
-rw-r--r--src/Protocol/Protocol125.cpp13
-rw-r--r--src/Protocol/Protocol125.h22
-rw-r--r--src/Protocol/Protocol132.cpp2
-rw-r--r--src/Protocol/Protocol132.h2
-rw-r--r--src/Protocol/Protocol16x.cpp11
-rw-r--r--src/Protocol/Protocol17x.cpp93
-rw-r--r--src/Protocol/Protocol17x.h2
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp2
-rw-r--r--src/Protocol/ProtocolRecognizer.h2
-rw-r--r--src/Root.cpp6
-rw-r--r--src/Simulator/DelayedFluidSimulator.cpp2
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp2
-rw-r--r--src/World.cpp22
-rw-r--r--src/World.h4
-rw-r--r--src/WorldStorage/FastNBT.h2
-rw-r--r--src/WorldStorage/FireworksSerializer.cpp252
-rw-r--r--src/WorldStorage/FireworksSerializer.h92
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp29
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h2
-rw-r--r--src/WorldStorage/WSSAnvil.cpp33
-rw-r--r--src/WorldStorage/WSSAnvil.h1
54 files changed, 948 insertions, 314 deletions
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 1890dcfe5..aa6ee05b3 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -677,6 +677,7 @@ void cLuaState::Push(Vector3i * a_Vector)
void cLuaState::Push(void * a_Ptr)
{
+ UNUSED(a_Ptr);
ASSERT(IsValid());
// Investigate the cause of this - what is the callstack?
diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp
index 374f3d6e3..cbfbb1b6a 100644
--- a/src/BlockEntities/DispenserEntity.cpp
+++ b/src/BlockEntities/DispenserEntity.cpp
@@ -116,7 +116,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
{
double TNTX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
double TNTZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
- m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 4, 0); // 4 seconds fuse, no initial velocity
+ m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 80, 0); // 80 ticks fuse, no initial velocity
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}
break;
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index 20336a07c..d1ecfdf7e 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -42,8 +42,6 @@ cBlockInfo::~cBlockInfo()
cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
{
- ASSERT(a_Type < 256);
-
return ms_Info[a_Type];
}
diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h
index 50c2e2ad5..3a3efb3cc 100644
--- a/src/Blocks/BlockHandler.h
+++ b/src/Blocks/BlockHandler.h
@@ -23,6 +23,8 @@ class cBlockHandler
{
public:
cBlockHandler(BLOCKTYPE a_BlockType);
+
+ virtual ~cBlockHandler() {}
/// Called when the block gets ticked either by a random tick or by a queued tick.
/// Note that the coords are chunk-relative!
diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h
index bbbe0ee84..ea8405597 100644
--- a/src/Blocks/BlockStairs.h
+++ b/src/Blocks/BlockStairs.h
@@ -25,6 +25,14 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
+ UNUSED(a_ChunkInterface);
+ UNUSED(a_BlockX);
+ UNUSED(a_BlockY);
+ UNUSED(a_BlockZ);
+ UNUSED(a_CursorX);
+ UNUSED(a_CursorY);
+ UNUSED(a_CursorZ);
+ UNUSED(a_BlockMeta);
a_BlockType = m_BlockType;
a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
switch (a_BlockFace)
diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h
index e28645142..708583e70 100644
--- a/src/Blocks/BlockVine.h
+++ b/src/Blocks/BlockVine.h
@@ -23,6 +23,10 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
+ UNUSED(a_Player);
+ UNUSED(a_CursorX);
+ UNUSED(a_CursorY);
+ UNUSED(a_CursorZ);
// TODO: Disallow placement where the vine doesn't attach to something properly
BLOCKTYPE BlockType = 0;
NIBBLETYPE BlockMeta;
@@ -161,11 +165,17 @@ public:
return false;
}
- virtual void OnUpdate(cWorld * a_World, int X, int Y, int Z)
+ virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
{
- if (a_World->GetBlock(X, Y - 1, Z) == E_BLOCK_AIR)
+ UNUSED(a_ChunkInterface);
+ UNUSED(a_WorldInterface);
+ UNUSED(a_BlockPluginInterface);
+
+ BLOCKTYPE Block;
+ a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block);
+ if (Block == E_BLOCK_AIR)
{
- a_World->SetBlock(X, Y - 1, Z, E_BLOCK_VINES, a_World->GetBlockMeta(X, Y, Z));
+ a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
}
}
diff --git a/src/Blocks/MetaRotater.h b/src/Blocks/MetaRotater.h
index d3664b6f1..dde88e6db 100644
--- a/src/Blocks/MetaRotater.h
+++ b/src/Blocks/MetaRotater.h
@@ -4,6 +4,15 @@
#pragma once
+// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it:
+#ifdef _MSC_VER
+ #pragma warning(disable: 4127) // Conditional expression is constant
+#endif
+
+
+
+
+
/*
Provides a mixin for rotations and reflections following the standard pattern of apply mask then use case.
@@ -29,6 +38,9 @@ public:
};
+
+
+
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta)
{
@@ -49,6 +61,8 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
+
+
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta)
{
@@ -69,6 +83,8 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
+
+
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta)
{
@@ -85,6 +101,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
+
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta)
{
@@ -97,3 +114,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
// Not Facing East or West; No change.
return a_Meta;
}
+
+
+
+
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index d2d3beb97..96a135562 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -44,10 +44,10 @@
-#if 0
+#ifdef SELF_TEST
/// Self-test of the VarInt-reading and writing code
-class cByteBufferSelfTest
+static class cByteBufferSelfTest
{
public:
cByteBufferSelfTest(void)
@@ -86,7 +86,7 @@ public:
cByteBuffer buf(3);
for (int i = 0; i < 1000; i++)
{
- int FreeSpace = buf.GetFreeSpace();
+ size_t FreeSpace = buf.GetFreeSpace();
assert(buf.GetReadableSpace() == 0);
assert(FreeSpace > 0);
assert(buf.Write("a", 1));
@@ -171,21 +171,22 @@ cByteBuffer::~cByteBuffer()
-bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
+bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
// Store the current free space for a check after writing:
- int CurFreeSpace = GetFreeSpace();
- int CurReadableSpace = GetReadableSpace();
- int WrittenBytes = 0;
+ size_t CurFreeSpace = GetFreeSpace();
+ size_t CurReadableSpace = GetReadableSpace();
+ size_t WrittenBytes = 0;
if (CurFreeSpace < a_Count)
{
return false;
}
- int TillEnd = m_BufferSize - m_WritePos;
+ ASSERT(m_BufferSize >= m_WritePos);
+ size_t TillEnd = m_BufferSize - m_WritePos;
if (TillEnd <= a_Count)
{
// Need to wrap around the ringbuffer end
@@ -216,16 +217,20 @@ bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
-int cByteBuffer::GetFreeSpace(void) const
+size_t cByteBuffer::GetFreeSpace(void) const
{
CHECK_THREAD;
CheckValid();
if (m_WritePos >= m_DataStart)
{
// Wrap around the buffer end:
+ ASSERT(m_BufferSize >= m_WritePos);
+ ASSERT((m_BufferSize - m_WritePos + m_DataStart) >= 1);
return m_BufferSize - m_WritePos + m_DataStart - 1;
}
// Single free space partition:
+ ASSERT(m_BufferSize >= m_WritePos);
+ ASSERT(m_BufferSize - m_WritePos >= 1);
return m_DataStart - m_WritePos - 1;
}
@@ -234,10 +239,12 @@ int cByteBuffer::GetFreeSpace(void) const
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
-int cByteBuffer::GetUsedSpace(void) const
+size_t cByteBuffer::GetUsedSpace(void) const
{
CHECK_THREAD;
CheckValid();
+ ASSERT(m_BufferSize >= GetFreeSpace());
+ ASSERT((m_BufferSize - GetFreeSpace()) >= 1);
return m_BufferSize - GetFreeSpace() - 1;
}
@@ -246,16 +253,18 @@ int cByteBuffer::GetUsedSpace(void) const
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
-int cByteBuffer::GetReadableSpace(void) const
+size_t cByteBuffer::GetReadableSpace(void) const
{
CHECK_THREAD;
CheckValid();
if (m_ReadPos > m_WritePos)
{
// Wrap around the buffer end:
+ ASSERT(m_BufferSize >= m_ReadPos);
return m_BufferSize - m_ReadPos + m_WritePos;
}
// Single readable space partition:
+ ASSERT(m_WritePos >= m_ReadPos);
return m_WritePos - m_ReadPos ;
}
@@ -263,7 +272,7 @@ int cByteBuffer::GetReadableSpace(void) const
-bool cByteBuffer::CanReadBytes(int a_Count) const
+bool cByteBuffer::CanReadBytes(size_t a_Count) const
{
CHECK_THREAD;
CheckValid();
@@ -274,7 +283,7 @@ bool cByteBuffer::CanReadBytes(int a_Count) const
-bool cByteBuffer::CanWriteBytes(int a_Count) const
+bool cByteBuffer::CanWriteBytes(size_t a_Count) const
{
CHECK_THREAD;
CheckValid();
@@ -650,15 +659,14 @@ bool cByteBuffer::WriteLEInt(int a_Value)
-bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count)
+bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
NEEDBYTES(a_Count);
char * Dst = (char *)a_Buffer; // So that we can do byte math
- int BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
- ASSERT(BytesToEndOfBuffer >= 0); // Sanity check
+ ASSERT(m_BufferSize >= m_ReadPos);
+ size_t BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
if (BytesToEndOfBuffer <= a_Count)
{
// Reading across the ringbuffer end, read the first part and adjust parameters:
@@ -684,14 +692,14 @@ bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count)
-bool cByteBuffer::WriteBuf(const void * a_Buffer, int a_Count)
+bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
PUTBYTES(a_Count);
char * Src = (char *)a_Buffer; // So that we can do byte math
- int BytesToEndOfBuffer = m_BufferSize - m_WritePos;
+ ASSERT(m_BufferSize >= m_ReadPos);
+ size_t BytesToEndOfBuffer = m_BufferSize - m_WritePos;
if (BytesToEndOfBuffer <= a_Count)
{
// Reading across the ringbuffer end, read the first part and adjust parameters:
@@ -714,22 +722,22 @@ bool cByteBuffer::WriteBuf(const void * a_Buffer, int a_Count)
-bool cByteBuffer::ReadString(AString & a_String, int a_Count)
+bool cByteBuffer::ReadString(AString & a_String, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
NEEDBYTES(a_Count);
a_String.clear();
a_String.reserve(a_Count);
- int BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
- ASSERT(BytesToEndOfBuffer >= 0); // Sanity check
+ ASSERT(m_BufferSize >= m_ReadPos);
+ size_t BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
if (BytesToEndOfBuffer <= a_Count)
{
// Reading across the ringbuffer end, read the first part and adjust parameters:
if (BytesToEndOfBuffer > 0)
{
a_String.assign(m_Buffer + m_ReadPos, BytesToEndOfBuffer);
+ ASSERT(a_Count >= BytesToEndOfBuffer);
a_Count -= BytesToEndOfBuffer;
}
m_ReadPos = 0;
@@ -767,11 +775,10 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars)
-bool cByteBuffer::SkipRead(int a_Count)
+bool cByteBuffer::SkipRead(size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
if (!CanReadBytes(a_Count))
{
return false;
@@ -809,6 +816,7 @@ bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes)
size_t num = (a_NumBytes > sizeof(buf)) ? sizeof(buf) : a_NumBytes;
VERIFY(ReadBuf(buf, num));
VERIFY(a_Dst.Write(buf, num));
+ ASSERT(a_NumBytes >= num);
a_NumBytes -= num;
}
return true;
@@ -846,13 +854,15 @@ void cByteBuffer::ReadAgain(AString & a_Out)
// Used by ProtoProxy to repeat communication twice, once for parsing and the other time for the remote party
CHECK_THREAD;
CheckValid();
- int DataStart = m_DataStart;
+ size_t DataStart = m_DataStart;
if (m_ReadPos < m_DataStart)
{
// Across the ringbuffer end, read the first part and adjust next part's start:
+ ASSERT(m_BufferSize >= m_DataStart);
a_Out.append(m_Buffer + m_DataStart, m_BufferSize - m_DataStart);
DataStart = 0;
}
+ ASSERT(m_ReadPos >= DataStart);
a_Out.append(m_Buffer + DataStart, m_ReadPos - DataStart);
}
@@ -860,7 +870,7 @@ void cByteBuffer::ReadAgain(AString & a_Out)
-void cByteBuffer::AdvanceReadPos(int a_Count)
+void cByteBuffer::AdvanceReadPos(size_t a_Count)
{
CHECK_THREAD;
CheckValid();
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index cbce119b1..ed2e10a55 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -31,25 +31,25 @@ public:
~cByteBuffer();
/// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
- bool Write(const char * a_Bytes, int a_Count);
+ bool Write(const char * a_Bytes, size_t a_Count);
/// Returns the number of bytes that can be successfully written to the ringbuffer
- int GetFreeSpace(void) const;
+ size_t GetFreeSpace(void) const;
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
- int GetUsedSpace(void) const;
+ size_t GetUsedSpace(void) const;
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
- int GetReadableSpace(void) const;
+ size_t GetReadableSpace(void) const;
/// Returns the current data start index. For debugging purposes.
int GetDataStart(void) const { return m_DataStart; }
/// Returns true if the specified amount of bytes are available for reading
- bool CanReadBytes(int a_Count) const;
+ bool CanReadBytes(size_t a_Count) const;
/// Returns true if the specified amount of bytes are available for writing
- bool CanWriteBytes(int a_Count) const;
+ bool CanWriteBytes(size_t a_Count) const;
// Read the specified datatype and advance the read pointer; return true if successfully read:
bool ReadChar (char & a_Value);
@@ -92,19 +92,19 @@ public:
bool WriteLEInt (int a_Value);
/// Reads a_Count bytes into a_Buffer; returns true if successful
- bool ReadBuf(void * a_Buffer, int a_Count);
+ bool ReadBuf(void * a_Buffer, size_t a_Count);
/// Writes a_Count bytes into a_Buffer; returns true if successful
- bool WriteBuf(const void * a_Buffer, int a_Count);
+ bool WriteBuf(const void * a_Buffer, size_t a_Count);
/// Reads a_Count bytes into a_String; returns true if successful
- bool ReadString(AString & a_String, int a_Count);
+ bool ReadString(AString & a_String, size_t a_Count);
/// Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String
bool ReadUTF16String(AString & a_String, int a_NumChars);
/// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer
- bool SkipRead(int a_Count);
+ bool SkipRead(size_t a_Count);
/// Reads all available data into a_Data
void ReadAll(AString & a_Data);
@@ -126,18 +126,18 @@ public:
protected:
char * m_Buffer;
- int m_BufferSize; // Total size of the ringbuffer
+ size_t m_BufferSize; // Total size of the ringbuffer
#ifdef _DEBUG
volatile unsigned long m_ThreadID; // Thread that is currently accessing the object, checked via cSingleThreadAccessChecker
#endif // _DEBUG
- int m_DataStart; // Where the data starts in the ringbuffer
- int m_WritePos; // Where the data ends in the ringbuffer
- int m_ReadPos; // Where the next read will start in the ringbuffer
+ size_t m_DataStart; // Where the data starts in the ringbuffer
+ size_t m_WritePos; // Where the data ends in the ringbuffer
+ size_t m_ReadPos; // Where the next read will start in the ringbuffer
/// Advances the m_ReadPos by a_Count bytes
- void AdvanceReadPos(int a_Count);
+ void AdvanceReadPos(size_t a_Count);
} ;
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index 7be2fa2df..63431f211 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -65,8 +65,8 @@ public:
enum
{
// Chunk dimensions:
- Width = 16,
- Height = 256,
+ Width = 16U,
+ Height = 256U,
NumBlocks = Width * Height * Width,
/// If the data is collected into a single buffer, how large it needs to be:
@@ -132,7 +132,7 @@ public:
}
- inline static unsigned int MakeIndexNoCheck(int x, int y, int z)
+ inline static unsigned int MakeIndexNoCheck(unsigned int x, unsigned int y, unsigned int z)
{
#if AXIS_ORDER == AXIS_ORDER_XZY
// For some reason, NOT using the Horner schema is faster. Weird.
@@ -240,7 +240,7 @@ public:
{
if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
{
- int Index = MakeIndexNoCheck(x, y, z);
+ unsigned int Index = MakeIndexNoCheck(x, y, z);
return (a_Buffer[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
}
ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!");
@@ -256,7 +256,7 @@ public:
return;
}
a_Buffer[a_BlockIdx / 2] = (
- (a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble
+ (a_Buffer[a_BlockIdx / 2] & (0xf0 >> (static_cast<NIBBLETYPE>(a_BlockIdx & 1) * 4))) | // The untouched nibble
((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set
);
}
@@ -282,13 +282,13 @@ public:
}
- inline static char GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
+ inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
{
return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z );
}
- inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, char a_Value )
+ inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value )
{
SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value );
}
@@ -306,6 +306,9 @@ The virtual methods are called in the same order as they're declared here.
class cChunkDataCallback abstract
{
public:
+
+ virtual ~cChunkDataCallback() {}
+
/** Called before any other callbacks to inform of the current coords
(only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()).
If false is returned, the chunk is skipped.
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index c677862eb..94c9f5f71 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -52,6 +52,9 @@
/** Maximum number of explosions to send this tick, server will start dropping if exceeded */
#define MAX_EXPLOSIONS_PER_TICK 20
+/** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */
+#define MAX_BLOCK_CHANGE_INTERACTIONS 20
+
/** How many ticks before the socket is closed after the client is destroyed (#31) */
static const int TICKS_BEFORE_CLOSE = 20;
@@ -96,8 +99,8 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
m_ShouldCheckDownloaded(false),
m_NumExplosionsThisTick(0),
m_UniqueID(0),
- m_Locale("en_GB"),
- m_HasSentPlayerChunk(false)
+ m_HasSentPlayerChunk(false),
+ m_Locale("en_GB")
{
m_Protocol = new cProtocolRecognizer(this);
@@ -700,6 +703,14 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status
);
+ m_NumBlockChangeInteractionsThisTick++;
+
+ if (!CheckBlockInteractionsRate())
+ {
+ Kick("Too many blocks were destroyed per unit time - hacked client?");
+ return;
+ }
+
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status))
{
@@ -707,12 +718,6 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
return;
}
-
- if (!CheckBlockInteractionsRate())
- {
- // Too many interactions per second, simply ignore. Probably a hacked client, so don't even send bak the block
- return;
- }
switch (a_Status)
{
@@ -944,7 +949,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- if (a_BlockFace > -1)
+ if (a_BlockFace != BLOCK_FACE_NONE)
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
@@ -955,7 +960,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
if (!CheckBlockInteractionsRate())
{
- LOGD("Too many block interactions, aborting placement");
+ Kick("Too many blocks were placed/interacted with per unit time - hacked client?");
return;
}
@@ -1466,7 +1471,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
-void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID)
+void cClientHandle::HandleEntityCrouch(int a_EntityID, bool a_IsCrouching)
{
if (a_EntityID != m_Player->GetUniqueID())
{
@@ -1474,35 +1479,37 @@ void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID)
return;
}
- switch (a_ActionID)
+ m_Player->SetCrouch(a_IsCrouching);
+}
+
+
+
+
+
+void cClientHandle::HandleEntityLeaveBed(int a_EntityID)
+{
+ if (a_EntityID != m_Player->GetUniqueID())
{
- case 1: // Crouch
- {
- m_Player->SetCrouch(true);
- break;
- }
- case 2: // Uncrouch
- {
- m_Player->SetCrouch(false);
- break;
- }
- case 3: // Leave bed
- {
- m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
- break;
- }
- case 4: // Start sprinting
- {
- m_Player->SetSprint(true);
- break;
- }
- case 5: // Stop sprinting
- {
- m_Player->SetSprint(false);
- SendPlayerMaxSpeed();
- break;
- }
+ // We should only receive entity actions from the entity that is performing the action
+ return;
}
+
+ m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
+}
+
+
+
+
+
+void cClientHandle::HandleEntitySprinting(int a_EntityID, bool a_IsSprinting)
+{
+ if (a_EntityID != m_Player->GetUniqueID())
+ {
+ // We should only receive entity actions from the entity that is performing the action
+ return;
+ }
+
+ m_Player->SetSprint(a_IsSprinting);
}
@@ -1632,28 +1639,12 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
{
ASSERT(m_Player != NULL);
ASSERT(m_Player->GetWorld() != NULL);
- /*
- // TODO: _X 2012_11_01: This needs a total re-thinking and rewriting
- int LastActionCnt = m_Player->GetLastBlockActionCnt();
- if ((m_Player->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1)
- {
- // Limit the number of block interactions per tick
- m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time.
- m_Player->SetLastBlockActionCnt(LastActionCnt + 1);
- if (m_Player->GetLastBlockActionCnt() > MAXBLOCKCHANGEINTERACTIONS)
- {
- // Kick if more than MAXBLOCKCHANGEINTERACTIONS per tick
- LOGWARN("Player %s tried to interact with a block too quickly! (could indicate bot) Was Kicked.", m_Username.c_str());
- Kick("You're a baaaaaad boy!");
- return false;
- }
- }
- else
+
+ if (m_NumBlockChangeInteractionsThisTick > MAX_BLOCK_CHANGE_INTERACTIONS)
{
- m_Player->SetLastBlockActionCnt(0); // Reset count
- m_Player->SetLastBlockActionTime(); // Player tried to interact with a block. Reset last block interation time.
+ return false;
}
- */
+
return true;
}
@@ -1726,8 +1717,9 @@ void cClientHandle::Tick(float a_Dt)
}
}
- // Reset explosion counter:
+ // Reset explosion & block change counters:
m_NumExplosionsThisTick = 0;
+ m_NumBlockChangeInteractionsThisTick = 0;
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 194533402..72b1c7d09 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -46,7 +46,6 @@ class cClientHandle : // tolua_export
public cSocketThreads::cCallback
{ // tolua_export
public:
- static const int MAXBLOCKCHANGEINTERACTIONS = 20; // 5 didn't help, 10 still doesn't work in Creative, 20 seems to have done the trick
#if defined(ANDROID_NDK)
static const int DEFAULT_VIEW_DISTANCE = 4; // The default ViewDistance (used when no value is set in Settings.ini)
@@ -188,7 +187,9 @@ public:
void HandleChat (const AString & a_Message);
void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem);
void HandleDisconnect (const AString & a_Reason);
- void HandleEntityAction (int a_EntityID, char a_ActionID);
+ void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching);
+ void HandleEntityLeaveBed (int a_EntityID);
+ void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting);
/** Called when the protocol handshake has been received (for protocol versions that support it;
otherwise the first instant when a username is received).
@@ -319,6 +320,9 @@ private:
/** Number of explosions sent this tick */
int m_NumExplosionsThisTick;
+
+ /** Number of place or break interactions this tick */
+ int m_NumBlockChangeInteractionsThisTick;
static int s_ClientCount;
int m_UniqueID;
diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp
index fb1a10cca..868182394 100644
--- a/src/CraftingRecipes.cpp
+++ b/src/CraftingRecipes.cpp
@@ -1,4 +1,4 @@
-
+
// CraftingRecipes.cpp
// Interfaces to the cCraftingRecipes class representing the storage of crafting recipes
@@ -762,9 +762,94 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti
Recipe->m_Ingredients.push_back(*itrS);
}
Recipe->m_Ingredients.insert(Recipe->m_Ingredients.end(), MatchedSlots.begin(), MatchedSlots.end());
+
+ // We use Recipe instead of a_Recipe because we want the wildcard ingredients' slot numbers as well, which was just added previously
+ HandleFireworks(a_CraftingGrid, Recipe.get(), a_GridStride, a_OffsetX, a_OffsetY);
+
return Recipe.release();
}
+
+void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY)
+{
+ // TODO: add support for more than one dye in the recipe
+ // A manual and temporary solution (listing everything) is in crafting.txt for fade colours, but a programmatic solutions needs to be done for everything else
+
+ if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_ROCKET)
+ {
+ for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
+ {
+ switch (itr->m_Item.m_ItemType)
+ {
+ case E_ITEM_FIREWORK_STAR:
+ {
+ // Result was a rocket, found a star - copy star data to rocket data
+ int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
+ a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
+ break;
+ }
+ case E_ITEM_GUNPOWDER:
+ {
+ // Gunpowder - increase flight time
+ a_Recipe->m_Result.m_FireworkItem.m_FlightTimeInTicks += 20;
+ break;
+ }
+ case E_ITEM_PAPER: break;
+ default: LOG("Unexpected item in firework rocket a_Recipe, was the crafting file fireworks section changed?"); break;
+ }
+ }
+ }
+ else if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_STAR)
+ {
+ std::vector<int> DyeColours;
+ bool FoundStar = false;
+
+ for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
+ {
+ switch (itr->m_Item.m_ItemType)
+ {
+ case E_ITEM_FIREWORK_STAR:
+ {
+ // Result was star, found another star - probably adding fade colours, but copy data over anyhow
+ FoundStar = true;
+ int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
+ a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
+ break;
+ }
+ case E_ITEM_DYE:
+ {
+ int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
+ DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye(a_CraftingGrid[GridID].m_ItemDamage));
+ break;
+ }
+ case E_ITEM_GUNPOWDER: break;
+ case E_ITEM_DIAMOND: a_Recipe->m_Result.m_FireworkItem.m_HasTrail = true; break;
+ case E_ITEM_GLOWSTONE_DUST: a_Recipe->m_Result.m_FireworkItem.m_HasFlicker = true; break;
+
+ case E_ITEM_FIRE_CHARGE: a_Recipe->m_Result.m_FireworkItem.m_Type = 1; break;
+ case E_ITEM_GOLD_NUGGET: a_Recipe->m_Result.m_FireworkItem.m_Type = 2; break;
+ case E_ITEM_FEATHER: a_Recipe->m_Result.m_FireworkItem.m_Type = 4; break;
+ case E_ITEM_HEAD: a_Recipe->m_Result.m_FireworkItem.m_Type = 3; break;
+ default: LOG("Unexpected item in firework star a_Recipe, was the crafting file fireworks section changed?"); break; // ermahgerd BARD ardmins
+ }
+ }
+
+ if (FoundStar && (!DyeColours.empty()))
+ {
+ // Found a star and a dye? Fade colours.
+ a_Recipe->m_Result.m_FireworkItem.m_FadeColours = DyeColours;
+ }
+ else if (!DyeColours.empty())
+ {
+ // Only dye? Normal colours.
+ a_Recipe->m_Result.m_FireworkItem.m_Colours = DyeColours;
+ }
+ }
+}
+
+
+
+
diff --git a/src/CraftingRecipes.h b/src/CraftingRecipes.h
index 9d92cbfab..90e41eddc 100644
--- a/src/CraftingRecipes.h
+++ b/src/CraftingRecipes.h
@@ -165,6 +165,9 @@ protected:
/// Checks if the grid matches the specified recipe, offset by the specified offsets. Returns a matched cRecipe * if so, or NULL if not matching. Caller must delete the return value!
cRecipe * MatchRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride, const cRecipe * a_Recipe, int a_OffsetX, int a_OffsetY);
+
+ /** Searches for anything firework related, and does the data setting if appropriate */
+ void HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY);
} ;
diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h
index 865d6dc50..f3b51d77b 100644
--- a/src/Entities/Floater.h
+++ b/src/Entities/Floater.h
@@ -11,7 +11,7 @@
class cFloater :
public cEntity
{
- typedef cFloater super;
+ typedef cEntity super;
public:
//tolua_end
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index f52a7b6d9..7f38aa35a 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -1031,9 +1031,9 @@ cMinecartWithChest::cMinecartWithChest(double a_X, double a_Y, double a_Z) :
-void cMinecartWithChest::SetSlot(int a_Idx, const cItem & a_Item)
+void cMinecartWithChest::SetSlot(size_t a_Idx, const cItem & a_Item)
{
- ASSERT((a_Idx >= 0) && (a_Idx < ARRAYCOUNT(m_Items)));
+ ASSERT(a_Idx < ARRAYCOUNT(m_Items));
m_Items[a_Idx] = a_Item;
}
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index 073e78953..ebdb576e0 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -122,7 +122,7 @@ public:
const cItem & GetSlot(int a_Idx) const { return m_Items[a_Idx]; }
cItem & GetSlot(int a_Idx) { return m_Items[a_Idx]; }
- void SetSlot(int a_Idx, const cItem & a_Item);
+ void SetSlot(size_t a_Idx, const cItem & a_Item);
protected:
@@ -193,4 +193,4 @@ public:
CLASS_PROTODEF(cMinecartWithHopper);
cMinecartWithHopper(double a_X, double a_Y, double a_Z);
-} ; \ No newline at end of file
+} ;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 42ee14cf3..ccdd151f3 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -10,18 +10,11 @@
#include "../BlockEntities/BlockEntity.h"
#include "../GroupManager.h"
#include "../Group.h"
-#include "../ChatColor.h"
-#include "../Item.h"
-#include "../Tracer.h"
#include "../Root.h"
#include "../OSSupport/Timer.h"
-#include "../MersenneTwister.h"
#include "../Chunk.h"
#include "../Items/ItemHandler.h"
-#include "../Vector3d.h"
-#include "../Vector3f.h"
-
#include "inifile/iniFile.h"
#include "json/json.h"
@@ -45,10 +38,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_Inventory(*this)
, m_CurrentWindow(NULL)
, m_InventoryWindow(NULL)
- , m_TimeLastPickupCheck(0.f)
, m_Color('-')
- , m_LastBlockActionTime(0)
- , m_LastBlockActionCnt(0)
, m_GameMode(eGameMode_NotSet)
, m_IP("")
, m_ClientHandle(a_Client)
@@ -86,7 +76,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
m_LastPlayerListTime = t1.GetNowTime();
m_TimeLastTeleportPacket = 0;
- m_TimeLastPickupCheck = 0;
m_PlayerName = a_PlayerName;
m_bDirtyPosition = true; // So chunks are streamed to player at spawn
@@ -1047,27 +1036,6 @@ void cPlayer::CloseWindowIfID(char a_WindowID, bool a_CanRefuse)
-void cPlayer::SetLastBlockActionTime()
-{
- if (m_World != NULL)
- {
- m_LastBlockActionTime = m_World->GetWorldAge() / 20.0f;
- }
-}
-
-
-
-
-
-void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt )
-{
- m_LastBlockActionCnt = a_LastBlockActionCnt;
-}
-
-
-
-
-
void cPlayer::SetGameMode(eGameMode a_GameMode)
{
if ((a_GameMode < gmMin) || (a_GameMode >= gmMax))
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index a795bb9eb..f9404dfaf 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -50,7 +50,7 @@ public:
/// Returns the curently equipped weapon; empty item if none
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
- /// Returns the currently equipped helmet; empty item if nonte
+ /// Returns the currently equipped helmet; empty item if none
virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
/// Returns the currently equipped chestplate; empty item if none
@@ -165,11 +165,6 @@ public:
// tolua_end
void SetIP(const AString & a_IP);
-
- float GetLastBlockActionTime() { return m_LastBlockActionTime; }
- int GetLastBlockActionCnt() { return m_LastBlockActionCnt; }
- void SetLastBlockActionCnt( int );
- void SetLastBlockActionTime();
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
void LoginSetGameMode(eGameMode a_GameMode);
@@ -416,12 +411,8 @@ protected:
cWindow * m_CurrentWindow;
cWindow * m_InventoryWindow;
- float m_TimeLastPickupCheck;
-
char m_Color;
- float m_LastBlockActionTime;
- int m_LastBlockActionCnt;
eGameMode m_GameMode;
AString m_IP;
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 03bc0c99d..12d2025ec 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -214,7 +214,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
-cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed)
+cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed)
{
Vector3d Speed;
if (a_Speed != NULL)
@@ -231,8 +231,15 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed);
case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed);
- case pkFirework: return new cFireworkEntity (a_Creator, a_X, a_Y, a_Z );
- // TODO: the rest
+ case pkFirework:
+ {
+ if (a_Item.m_FireworkItem.m_Colours.empty())
+ {
+ return NULL;
+ }
+
+ return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, a_Item);
+ }
}
LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind);
@@ -276,6 +283,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
case pkExpBottle: return "ThrownExpBottle";
case pkSplashPotion: return "ThrownPotion";
case pkWitherSkull: return "WitherSkull";
+ case pkFirework: return "Firework";
case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
}
ASSERT(!"Unhandled projectile entity kind!");
@@ -693,8 +701,10 @@ void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFireworkEntity :
-cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z) :
-super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
+super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
+ m_ExplodeTimer(0),
+ m_FireworkItem(a_Item)
{
}
@@ -702,30 +712,20 @@ super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
-void cFireworkEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
- if ((a_HitFace != BLOCK_FACE_BOTTOM) && (a_HitFace != BLOCK_FACE_NONE))
+ int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
+ int PosY = POSY_TOINT;
+
+ if ((PosY < 0) || (PosY >= cChunkDef::Height))
{
- return;
+ goto setspeed;
}
- SetSpeed(0, 0, 0);
- SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ());
-
- m_IsInGround = true;
-
- BroadcastMovementUpdate();
-}
-
-
-
-
-
-void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
-{
if (m_IsInGround)
{
- if (a_Chunk.GetBlock((int)GetPosX(), (int)GetPosY() + 1, (int)GetPosZ()) == E_BLOCK_AIR)
+ if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
{
m_IsInGround = false;
}
@@ -734,28 +734,35 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
return;
}
}
+ else
+ {
+ if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
+ {
+ OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
+ return;
+ }
+ }
- Vector3d PerTickSpeed = GetSpeed() / 20;
- Vector3d Pos = GetPosition();
+setspeed:
+ AddSpeedY(1);
+ AddPosition(GetSpeed() * (a_Dt / 1000));
+}
- // Trace the tick's worth of movement as a line:
- Vector3d NextPos = Pos + PerTickSpeed;
- cProjectileTracerCallback TracerCallback(this);
- if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
+
+
+
+
+void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
{
- // Something has been hit, abort all other processing
- return;
+ m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE);
+ Destroy();
}
- // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff
-
- // Update the position:
- SetPosition(NextPos);
- // Add slowdown and gravity effect to the speed:
- Vector3d NewSpeed(GetSpeed());
- NewSpeed.y += 2;
- NewSpeed *= TracerCallback.GetSlowdownCoeff();
- SetSpeed(NewSpeed);
+ m_ExplodeTimer++;
}
diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h
index e80592999..fac592d16 100644
--- a/src/Entities/ProjectileEntity.h
+++ b/src/Entities/ProjectileEntity.h
@@ -46,7 +46,7 @@ public:
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
- static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL);
+ static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed = NULL);
/// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace);
@@ -305,13 +305,19 @@ public:
CLASS_PROTODEF(cFireworkEntity);
- cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z);
+ cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
+ const cItem & GetItem(void) const { return m_FireworkItem; }
protected:
// cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+private:
+
+ int m_ExplodeTimer;
+ cItem m_FireworkItem;
// tolua_begin
diff --git a/src/Entities/TNTEntity.cpp b/src/Entities/TNTEntity.cpp
index 339107b2e..02f31f5bb 100644
--- a/src/Entities/TNTEntity.cpp
+++ b/src/Entities/TNTEntity.cpp
@@ -8,10 +8,9 @@
-cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec) :
+cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, int a_FuseTicks) :
super(etTNT, a_X, a_Y, a_Z, 0.98, 0.98),
- m_Counter(0),
- m_MaxFuseTime(a_FuseTimeInSec)
+ m_FuseTicks(a_FuseTicks)
{
}
@@ -19,10 +18,9 @@ cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSe
-cTNTEntity::cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec) :
+cTNTEntity::cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks) :
super(etTNT, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
- m_Counter(0),
- m_MaxFuseTime(a_FuseTimeInSec)
+ m_FuseTicks(a_FuseTicks)
{
}
@@ -42,18 +40,27 @@ void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle)
+void cTNTEntity::Explode(void)
+{
+ m_FuseTicks = 0;
+ Destroy(true);
+ LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
+ m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
+}
+
+
+
+
+
void cTNTEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
BroadcastMovementUpdate();
- float delta_time = a_Dt / 1000; // Convert miliseconds to seconds
- m_Counter += delta_time;
- if (m_Counter > m_MaxFuseTime) // Check if we go KABOOOM
+
+ m_FuseTicks -= 1;
+ if (m_FuseTicks <= 0)
{
- Destroy(true);
- LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
- m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
- return;
+ Explode();
}
}
diff --git a/src/Entities/TNTEntity.h b/src/Entities/TNTEntity.h
index d1fcae766..116f5a8cb 100644
--- a/src/Entities/TNTEntity.h
+++ b/src/Entities/TNTEntity.h
@@ -16,19 +16,28 @@ public:
// tolua_end
CLASS_PROTODEF(cTNTEntity);
- cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec);
- cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec);
+ cTNTEntity(double a_X, double a_Y, double a_Z, int a_FuseTicks = 80);
+ cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks = 80);
// cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- double GetCounterTime(void) const { return m_Counter; } // tolua_export
- double GetMaxFuseTime(void) const { return m_MaxFuseTime; } // tolua_export
+
+ // tolua_begin
+
+ /** Explode the tnt */
+ void Explode(void);
+
+ /** Returns the fuse ticks until the tnt will explode */
+ int GetFuseTicks(void) const { return m_FuseTicks; }
+
+ /** Set the fuse ticks until the tnt will explode */
+ void SetFuseTicks(int a_FuseTicks) { m_FuseTicks = a_FuseTicks; }
+
+ // tolua_end
protected:
- double m_Counter; ///< How much time has elapsed since the object was created, in seconds
- double m_MaxFuseTime; ///< How long the fuse is, in seconds
+ int m_FuseTicks; ///< How much ticks is left, while the tnt will explode
}; // tolua_export
diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp
index d9acc57bb..28dc37567 100644
--- a/src/Generating/MineShafts.cpp
+++ b/src/Generating/MineShafts.cpp
@@ -69,6 +69,8 @@ public:
m_BoundingBox(a_BoundingBox)
{
}
+
+ virtual ~cMineShaft() {}
/// Returns true if this mineshaft intersects the specified cuboid
bool DoesIntersect(const cCuboid & a_Other)
diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp
index a660285d1..4909587b1 100644
--- a/src/Generating/Trees.cpp
+++ b/src/Generating/Trees.cpp
@@ -595,7 +595,7 @@ void GetPineTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise
{
break;
}
- ASSERT(LayerSize < ARRAYCOUNT(BigOs));
+ ASSERT((size_t)LayerSize < ARRAYCOUNT(BigOs));
PushCoordBlocks(a_BlockX, h, a_BlockZ, a_OtherBlocks, BigOs[LayerSize].Coords, BigOs[LayerSize].Count, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
h--;
}
diff --git a/src/Item.cpp b/src/Item.cpp
index 9170006b6..61d57e763 100644
--- a/src/Item.cpp
+++ b/src/Item.cpp
@@ -1,4 +1,4 @@
-
+
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Item.h"
@@ -139,6 +139,16 @@ void cItem::GetJson(Json::Value & a_OutValue) const
{
a_OutValue["Lore"] = m_Lore;
}
+
+ if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ a_OutValue["Flicker"] = m_FireworkItem.m_HasFlicker;
+ a_OutValue["Trail"] = m_FireworkItem.m_HasTrail;
+ a_OutValue["Type"] = m_FireworkItem.m_Type;
+ a_OutValue["FlightTimeInTicks"] = m_FireworkItem.m_FlightTimeInTicks;
+ a_OutValue["Colours"] = m_FireworkItem.ColoursToString(m_FireworkItem);
+ a_OutValue["FadeColours"] = m_FireworkItem.FadeColoursToString(m_FireworkItem);
+ }
}
}
@@ -157,6 +167,16 @@ void cItem::FromJson(const Json::Value & a_Value)
m_Enchantments.AddFromString(a_Value.get("ench", "").asString());
m_CustomName = a_Value.get("Name", "").asString();
m_Lore = a_Value.get("Lore", "").asString();
+
+ if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ m_FireworkItem.m_HasFlicker = a_Value.get("Flicker", false).asBool();
+ m_FireworkItem.m_HasTrail = a_Value.get("Trail", false).asBool();
+ m_FireworkItem.m_Type = (NIBBLETYPE)a_Value.get("Type", 0).asInt();
+ m_FireworkItem.m_FlightTimeInTicks = (short)a_Value.get("FlightTimeInTicks", 0).asInt();
+ m_FireworkItem.ColoursFromString(a_Value.get("Colours", "").asString(), m_FireworkItem);
+ m_FireworkItem.FadeColoursFromString(a_Value.get("FadeColours", "").asString(), m_FireworkItem);
+ }
}
}
diff --git a/src/Item.h b/src/Item.h
index cc3b3c961..4bdfb12dd 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -11,6 +11,7 @@
#include "Defines.h"
#include "Enchantments.h"
+#include "WorldStorage/FireworksSerializer.h"
@@ -38,7 +39,8 @@ public:
m_ItemCount(0),
m_ItemDamage(0),
m_CustomName(""),
- m_Lore("")
+ m_Lore(""),
+ m_FireworkItem()
{
}
@@ -57,7 +59,8 @@ public:
m_ItemDamage (a_ItemDamage),
m_Enchantments(a_Enchantments),
m_CustomName (a_CustomName),
- m_Lore (a_Lore)
+ m_Lore (a_Lore),
+ m_FireworkItem()
{
if (!IsValidItem(m_ItemType))
{
@@ -77,7 +80,8 @@ public:
m_ItemDamage (a_CopyFrom.m_ItemDamage),
m_Enchantments(a_CopyFrom.m_Enchantments),
m_CustomName (a_CopyFrom.m_CustomName),
- m_Lore (a_CopyFrom.m_Lore)
+ m_Lore (a_CopyFrom.m_Lore),
+ m_FireworkItem(a_CopyFrom.m_FireworkItem)
{
}
@@ -90,6 +94,7 @@ public:
m_Enchantments.Clear();
m_CustomName = "";
m_Lore = "";
+ m_FireworkItem.EmptyData();
}
@@ -115,7 +120,8 @@ public:
(m_ItemDamage == a_Item.m_ItemDamage) &&
(m_Enchantments == a_Item.m_Enchantments) &&
(m_CustomName == a_Item.m_CustomName) &&
- (m_Lore == a_Item.m_Lore)
+ (m_Lore == a_Item.m_Lore) &&
+ m_FireworkItem.IsEqualTo(a_Item.m_FireworkItem)
);
}
@@ -177,6 +183,8 @@ public:
cEnchantments m_Enchantments;
AString m_CustomName;
AString m_Lore;
+
+ cFireworkItem m_FireworkItem;
};
// tolua_end
diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h
index ef3f37a7a..5b6c239cc 100644
--- a/src/Items/ItemHandler.h
+++ b/src/Items/ItemHandler.h
@@ -21,6 +21,9 @@ class cItemHandler
public:
cItemHandler(int a_ItemType);
+ // Force virtual destructor
+ virtual ~cItemHandler() {}
+
/// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False
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);
diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h
index cc7daeb08..18873e911 100644
--- a/src/Items/ItemLighter.h
+++ b/src/Items/ItemLighter.h
@@ -33,8 +33,8 @@ public:
case E_BLOCK_TNT:
{
// Activate the TNT:
- a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
- a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
+ a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f);
+ a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0);
break;
}
diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h
index 46049f961..c6a4e714e 100644
--- a/src/Items/ItemThrowable.h
+++ b/src/Items/ItemThrowable.h
@@ -35,7 +35,7 @@ public:
Vector3d Pos = a_Player->GetThrowStartPos();
Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
- a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed);
+ a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed);
return true;
}
@@ -127,13 +127,13 @@ public:
return false;
}
+ a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem());
+
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
- a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, 0);
-
return true;
}
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index 4761103e5..c64360153 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -68,17 +68,28 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
{
- // The sheep should not move when he's eating so only handle the physics.
+ super::Tick(a_Dt, a_Chunk);
+ int PosX = POSX_TOINT;
+ int PosY = POSY_TOINT - 1;
+ int PosZ = POSZ_TOINT;
+
+ if ((PosY <= 0) || (PosY > cChunkDef::Height))
+ {
+ return;
+ }
+
if (m_TimeToStopEating > 0)
{
- HandlePhysics(a_Dt, a_Chunk);
+ m_bMovingToDestination = false; // The sheep should not move when he's eating
m_TimeToStopEating--;
+
if (m_TimeToStopEating == 0)
{
- if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
+ if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) // Make sure grass hasn't been destroyed in the meantime
{
- // The sheep ate the grass so we change it to dirt.
- m_World->SetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ(), E_BLOCK_DIRT, 0);
+ // The sheep ate the grass so we change it to dirt
+ m_World->SetBlock(PosX, PosY, PosZ, E_BLOCK_DIRT, 0);
+ GetWorld()->BroadcastSoundParticleEffect(2001, PosX, PosY, PosX, E_BLOCK_GRASS);
m_IsSheared = false;
m_World->BroadcastEntityMetadata(*this);
}
@@ -86,12 +97,11 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
}
else
{
- super::Tick(a_Dt, a_Chunk);
if (m_World->GetTickRandomNumber(600) == 1)
{
- if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
+ if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
{
- m_World->BroadcastEntityStatus(*this, 10);
+ m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING);
m_TimeToStopEating = 40;
}
}
diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h
index fcd2ce11f..b2eb5950f 100644
--- a/src/OSSupport/SocketThreads.h
+++ b/src/OSSupport/SocketThreads.h
@@ -103,7 +103,7 @@ private:
public:
cSocketThread(cSocketThreads * a_Parent);
- ~cSocketThread();
+ virtual ~cSocketThread();
// All these methods assume parent's m_CS is locked
bool HasEmptySlot(void) const {return m_NumSlots < MAX_SLOTS; }
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index b5560f7c1..d3383bf0d 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -52,7 +52,7 @@ public:
virtual ~cProtocol() {}
/// Called when client sends some data
- virtual void DataReceived(const char * a_Data, int a_Size) = 0;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) = 0;
// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0;
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 3980350f5..50ebb6d43 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -1186,7 +1186,7 @@ void cProtocol125::SendData(const char * a_Data, int a_Size)
-void cProtocol125::DataReceived(const char * a_Data, int a_Size)
+void cProtocol125::DataReceived(const char * a_Data, size_t a_Size)
{
if (!m_ReceivedData.Write(a_Data, a_Size))
{
@@ -1375,7 +1375,16 @@ int cProtocol125::ParseEntityAction(void)
{
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
HANDLE_PACKET_READ(ReadChar, char, ActionID);
- m_Client->HandleEntityAction(EntityID, ActionID);
+
+ switch (ActionID)
+ {
+ case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch
+ case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch
+ case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed
+ case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting
+ case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting
+ }
+
return PARSE_OK;
}
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index 1d1484a60..aca24c03a 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -11,6 +11,7 @@
#include "Protocol.h"
#include "../ByteBuffer.h"
+#include "../Entities/Painting.h"
@@ -24,7 +25,7 @@ public:
cProtocol125(cClientHandle * a_Client);
/// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
@@ -57,9 +58,17 @@ public:
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
- virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override {} // This protocol doesn't support such message
+ virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override
+ {
+ // This protocol doesn't support such message
+ UNUSED(a_ID);
+ UNUSED(a_Scale);
+ }
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
- virtual void SendPaintingSpawn (const cPainting & a_Painting) override {};
+ virtual void SendPaintingSpawn (const cPainting & a_Painting) override
+ {
+ UNUSED(a_Painting);
+ };
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
@@ -73,7 +82,12 @@ public:
virtual void SendRespawn (void) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
- virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override {} // This protocol doesn't support such message
+ virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override
+ {
+ UNUSED(a_Name);
+ UNUSED(a_DisplayName);
+ UNUSED(a_Mode);
+ } // This protocol doesn't support such message
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index 1f9222a69..8df550c7b 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -108,7 +108,7 @@ cProtocol132::~cProtocol132()
-void cProtocol132::DataReceived(const char * a_Data, int a_Size)
+void cProtocol132::DataReceived(const char * a_Data, size_t a_Size)
{
if (m_IsEncrypted)
{
diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h
index 89f4636f5..0702fbf5a 100644
--- a/src/Protocol/Protocol132.h
+++ b/src/Protocol/Protocol132.h
@@ -40,7 +40,7 @@ public:
virtual ~cProtocol132();
/// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
// Sending commands (alphabetically sorted):
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp
index cfa27b3c4..f6ec0a199 100644
--- a/src/Protocol/Protocol16x.cpp
+++ b/src/Protocol/Protocol16x.cpp
@@ -184,7 +184,16 @@ int cProtocol161::ParseEntityAction(void)
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
HANDLE_PACKET_READ(ReadChar, char, ActionID);
HANDLE_PACKET_READ(ReadBEInt, int, UnknownHorseVal);
- m_Client->HandleEntityAction(EntityID, ActionID);
+
+ switch (ActionID)
+ {
+ case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch
+ case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch
+ case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed
+ case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting
+ case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting
+ }
+
return PARSE_OK;
}
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 18646254f..8c800036e 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -98,7 +98,7 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
-void cProtocol172::DataReceived(const char * a_Data, int a_Size)
+void cProtocol172::DataReceived(const char * a_Data, size_t a_Size)
{
if (m_IsEncrypted)
{
@@ -1244,7 +1244,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (m_ReceivedData.GetReadableSpace() > 0)
{
AString AllData;
- int OldReadableSpace = m_ReceivedData.GetReadableSpace();
+ size_t OldReadableSpace = m_ReceivedData.GetReadableSpace();
m_ReceivedData.ReadAll(AllData);
m_ReceivedData.ResetRead();
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
@@ -1366,7 +1366,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (g_ShouldLogCommIn && (m_ReceivedData.GetReadableSpace() > 0))
{
AString AllData;
- int OldReadableSpace = m_ReceivedData.GetReadableSpace();
+ size_t OldReadableSpace = m_ReceivedData.GetReadableSpace();
m_ReceivedData.ReadAll(AllData);
m_ReceivedData.ResetRead();
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
@@ -1732,7 +1732,15 @@ void cProtocol172::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEInt, int, PlayerID);
HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Action);
HANDLE_READ(a_ByteBuffer, ReadBEInt, int, JumpBoost);
- m_Client->HandleEntityAction(PlayerID, Action);
+
+ switch (Action)
+ {
+ case 1: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch
+ case 2: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch
+ case 3: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed
+ case 4: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting
+ case 5: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting
+ }
}
@@ -2071,36 +2079,47 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
// Load enchantments and custom display names from the NBT data:
for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
{
- if (
- (NBT.GetType(tag) == TAG_List) &&
- (
- (NBT.GetName(tag) == "ench") ||
- (NBT.GetName(tag) == "StoredEnchantments")
- )
- )
+ AString TagName = NBT.GetName(tag);
+ switch (NBT.GetType(tag))
{
- EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag);
- }
- else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag
- {
- for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
+ case TAG_List:
{
- if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
+ if ((TagName == "ench") || (TagName == "StoredEnchantments")) // Enchantments tags
{
- a_Item.m_CustomName = NBT.GetString(displaytag);
+ EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag);
}
- else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
+ break;
+ }
+ case TAG_Compound:
+ {
+ if (TagName == "display") // Custom name and lore tag
{
- AString Lore;
-
- for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
+ for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
{
- AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
+ if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
+ {
+ a_Item.m_CustomName = NBT.GetString(displaytag);
+ }
+ else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
+ {
+ AString Lore;
+
+ for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
+ {
+ AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
+ }
+
+ a_Item.m_Lore = Lore;
+ }
}
-
- a_Item.m_Lore = Lore;
}
+ else if ((TagName == "Fireworks") || (TagName == "Explosion"))
+ {
+ cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, NBT, tag, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
+ break;
}
+ default: LOGD("Unimplemented NBT data when parsing!"); break;
}
}
}
@@ -2264,7 +2283,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
WriteByte (a_Item.m_ItemCount);
WriteShort(a_Item.m_ItemDamage);
- if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty())
+ if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR))
{
WriteShort(-1);
return;
@@ -2303,6 +2322,10 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
}
Writer.EndCompound();
}
+ if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
@@ -2479,10 +2502,22 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
}
case cEntity::etProjectile:
{
- if (((cProjectileEntity &)a_Entity).GetProjectileKind() == cProjectileEntity::pkArrow)
+ cProjectileEntity & Projectile = (cProjectileEntity &)a_Entity;
+ switch (Projectile.GetProjectileKind())
{
- WriteByte(0x10);
- WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
+ case cProjectileEntity::pkArrow:
+ {
+ WriteByte(0x10);
+ WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
+ break;
+ }
+ case cProjectileEntity::pkFirework:
+ {
+ WriteByte(0xA8);
+ WriteItem(((const cFireworkEntity &)a_Entity).GetItem());
+ break;
+ }
+ default: break;
}
break;
}
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 113501568..41163009e 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -56,7 +56,7 @@ public:
cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
/** Called when client sends some data: */
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/** Sending stuff to clients (alphabetically sorted): */
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 84b052146..3b9003e60 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -68,7 +68,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
-void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size)
+void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size)
{
if (m_Protocol == NULL)
{
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index 6aaafedeb..d7fb8fad2 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -59,7 +59,7 @@ public:
static AString GetVersionTextFromInt(int a_ProtocolVersion);
/// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
diff --git a/src/Root.cpp b/src/Root.cpp
index 78c94888d..69f18104e 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -593,7 +593,6 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
unsigned m_NameLength;
const AString m_PlayerName;
- cPlayerListCallback & m_Callback;
virtual bool Item (cPlayer * a_pPlayer)
{
unsigned int Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName());
@@ -615,18 +614,17 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
}
public:
- cCallback (const AString & a_PlayerName, cPlayerListCallback & a_Callback) :
+ cCallback (const AString & a_PlayerName) :
m_BestRating(0),
m_NameLength(a_PlayerName.length()),
m_PlayerName(a_PlayerName),
- m_Callback(a_Callback),
m_BestMatch(NULL),
m_NumMatches(0)
{}
cPlayer * m_BestMatch;
unsigned m_NumMatches;
- } Callback (a_PlayerName, a_Callback);
+ } Callback (a_PlayerName);
ForEachPlayer( Callback );
if (Callback.m_NumMatches == 1)
diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp
index 3d2170e44..bc5158d95 100644
--- a/src/Simulator/DelayedFluidSimulator.cpp
+++ b/src/Simulator/DelayedFluidSimulator.cpp
@@ -20,7 +20,7 @@
bool cDelayedFluidSimulatorChunkData::cSlot::Add(int a_RelX, int a_RelY, int a_RelZ)
{
ASSERT(a_RelZ >= 0);
- ASSERT(a_RelZ < ARRAYCOUNT(m_Blocks));
+ ASSERT(a_RelZ < static_cast<int>(ARRAYCOUNT(m_Blocks)));
cCoordWithIntVector & Blocks = m_Blocks[a_RelZ];
int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index f377b0aa7..ca2ef4b1a 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -838,7 +838,7 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_
if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
{
m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
- m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
+ m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
}
}
diff --git a/src/World.cpp b/src/World.cpp
index f6d277663..a9db6bf00 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1726,10 +1726,10 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType
-void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff)
+void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff)
{
UNUSED(a_InitialVelocityCoeff);
- cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTimeInSec);
+ cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks);
TNT->Initialize(this);
// TODO: Add a bit of speed in horiz and vert axes, based on the a_InitialVelocityCoeff
}
@@ -2980,9 +2980,9 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
-int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed)
+int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed)
{
- cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Speed);
+ cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
if (Projectile == NULL)
{
return -1;
@@ -3005,18 +3005,18 @@ void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Resul
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(), end = m_Players.end(); itr != end; ++itr)
{
- size_t LastSpace = a_Text.find_last_of(" "); //Find the position of the last space
+ size_t LastSpace = a_Text.find_last_of(" "); // Find the position of the last space
- std::string LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); //Find the last word
- std::string PlayerName ((*itr)->GetName());
- std::size_t Found = PlayerName.find(LastWord); //Try to find last word in playername
+ AString LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); // Find the last word
+ AString PlayerName ((*itr)->GetName());
+ size_t Found = PlayerName.find(LastWord); // Try to find last word in playername
- if (Found!=0)
+ if (Found == AString::npos)
{
- continue; //No match
+ continue; // No match
}
- a_Results.push_back((*itr)->GetName()); //Match!
+ a_Results.push_back(PlayerName); // Match!
}
}
diff --git a/src/World.h b/src/World.h
index 0a0939dd1..d48db5911 100644
--- a/src/World.h
+++ b/src/World.h
@@ -445,7 +445,7 @@ public:
int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward);
/** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided */
- void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);
+ void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1);
// tolua_end
@@ -708,7 +708,7 @@ public:
int SpawnMobFinalize(cMonster* a_Monster);
/** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */
- int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
+ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed = NULL); // tolua_export
/** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */
int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h
index 01a9ad274..1b8b09c21 100644
--- a/src/WorldStorage/FastNBT.h
+++ b/src/WorldStorage/FastNBT.h
@@ -309,7 +309,7 @@ protected:
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
+ static const int MAX_STACK = 50; // Highly doubtful that an NBT would be constructed this many levels deep
// These two fields emulate a stack. A raw array is used due to speed issues - no reallocations are allowed.
sParent m_Stack[MAX_STACK];
diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp
new file mode 100644
index 000000000..1f05b470d
--- /dev/null
+++ b/src/WorldStorage/FireworksSerializer.cpp
@@ -0,0 +1,252 @@
+
+#include "Globals.h"
+#include "FireworksSerializer.h"
+#include "WorldStorage/FastNBT.h"
+
+
+
+
+
+void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type)
+{
+ switch (a_Type)
+ {
+ case E_ITEM_FIREWORK_ROCKET:
+ {
+ a_Writer.BeginCompound("Fireworks");
+ a_Writer.AddByte("Flight", a_FireworkItem.m_FlightTimeInTicks / 20);
+ a_Writer.BeginList("Explosions", TAG_Compound);
+ a_Writer.BeginCompound("");
+ a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
+ a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
+ a_Writer.AddByte("Type", a_FireworkItem.m_Type);
+ a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
+ a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
+ a_Writer.EndCompound();
+ a_Writer.EndList();
+ a_Writer.EndCompound();
+ break;
+ }
+ case E_ITEM_FIREWORK_STAR:
+ {
+ a_Writer.BeginCompound("Explosion");
+ a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
+ a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
+ a_Writer.AddByte("Type", a_FireworkItem.m_Type);
+ if (!a_FireworkItem.m_Colours.empty())
+ {
+ a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
+ }
+ if (!a_FireworkItem.m_FadeColours.empty())
+ {
+ a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
+ }
+ a_Writer.EndCompound();
+ break;
+ }
+ default: ASSERT(!"Unhandled firework item!"); break;
+ }
+}
+
+
+
+
+
+void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type)
+{
+ if (a_TagIdx < 0)
+ {
+ return;
+ }
+
+ switch (a_Type)
+ {
+ case E_ITEM_FIREWORK_STAR:
+ {
+ for (int explosiontag = a_NBT.GetFirstChild(a_TagIdx); explosiontag >= 0; explosiontag = a_NBT.GetNextSibling(explosiontag))
+ {
+ eTagType TagType = a_NBT.GetType(explosiontag);
+ if (TagType == TAG_Byte) // Custon name tag
+ {
+ AString ExplosionName = a_NBT.GetName(explosiontag);
+
+ if (ExplosionName == "Flicker")
+ {
+ a_FireworkItem.m_HasFlicker = (a_NBT.GetByte(explosiontag) == 1);
+ }
+ else if (ExplosionName == "Trail")
+ {
+ a_FireworkItem.m_HasTrail = (a_NBT.GetByte(explosiontag) == 1);
+ }
+ else if (ExplosionName == "Type")
+ {
+ a_FireworkItem.m_Type = a_NBT.GetByte(explosiontag);
+ }
+ }
+ else if (TagType == TAG_IntArray)
+ {
+ AString ExplosionName = a_NBT.GetName(explosiontag);
+
+ if (ExplosionName == "Colors")
+ {
+ // Divide by four as data length returned in bytes
+ int DataLength = a_NBT.GetDataLength(explosiontag) / 4;
+ if (DataLength == 0)
+ {
+ continue;
+ }
+
+ const int * ColourData = (const int *)(a_NBT.GetData(explosiontag));
+ for (int i = 0; i < DataLength; i++)
+ {
+ a_FireworkItem.m_Colours.push_back(ntohl(ColourData[i]));
+ }
+ }
+ else if (ExplosionName == "FadeColors")
+ {
+ int DataLength = a_NBT.GetDataLength(explosiontag) / 4;
+ if (DataLength == 0)
+ {
+ continue;
+ }
+
+ const int * FadeColourData = (const int *)(a_NBT.GetData(explosiontag));
+ for (int i = 0; i < DataLength; i++)
+ {
+ a_FireworkItem.m_FadeColours.push_back(ntohl(FadeColourData[i]));
+ }
+ }
+ }
+ }
+ break;
+ }
+ case E_ITEM_FIREWORK_ROCKET:
+ {
+ for (int fireworkstag = a_NBT.GetFirstChild(a_TagIdx); fireworkstag >= 0; fireworkstag = a_NBT.GetNextSibling(fireworkstag))
+ {
+ eTagType TagType = a_NBT.GetType(fireworkstag);
+ if (TagType == TAG_Byte) // Custon name tag
+ {
+ if (a_NBT.GetName(fireworkstag) == "Flight")
+ {
+ a_FireworkItem.m_FlightTimeInTicks = a_NBT.GetByte(fireworkstag) * 20;
+ }
+ }
+ else if ((TagType == TAG_List) && (a_NBT.GetName(fireworkstag) == "Explosions"))
+ {
+ int ExplosionsChild = a_NBT.GetFirstChild(fireworkstag);
+ if ((a_NBT.GetType(ExplosionsChild) == TAG_Compound) && (a_NBT.GetName(ExplosionsChild).empty()))
+ {
+ ParseFromNBT(a_FireworkItem, a_NBT, ExplosionsChild, E_ITEM_FIREWORK_STAR);
+ }
+ }
+ }
+ break;
+ }
+ default: ASSERT(!"Unhandled firework item!"); break;
+ }
+}
+
+
+
+
+
+AString cFireworkItem::ColoursToString(const cFireworkItem & a_FireworkItem)
+{
+ AString Result;
+
+ for (std::vector<int>::const_iterator itr = a_FireworkItem.m_Colours.begin(); itr != a_FireworkItem.m_Colours.end(); ++itr)
+ {
+ AppendPrintf(Result, "%i;", *itr);
+ }
+
+ return Result;
+}
+
+
+
+
+
+void cFireworkItem::ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
+{
+ AStringVector Split = StringSplit(a_String, ";");
+
+ for (size_t itr = 0; itr < Split.size(); ++itr)
+ {
+ if (Split[itr].empty())
+ {
+ continue;
+ }
+
+ a_FireworkItem.m_Colours.push_back(atoi(Split[itr].c_str()));
+ }
+}
+
+
+
+
+
+AString cFireworkItem::FadeColoursToString(const cFireworkItem & a_FireworkItem)
+{
+ AString Result;
+
+ for (std::vector<int>::const_iterator itr = a_FireworkItem.m_FadeColours.begin(); itr != a_FireworkItem.m_FadeColours.end(); ++itr)
+ {
+ AppendPrintf(Result, "%i;", *itr);
+ }
+
+ return Result;
+}
+
+
+
+
+
+void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
+{
+ AStringVector Split = StringSplit(a_String, ";");
+
+ for (size_t itr = 0; itr < Split.size(); ++itr)
+ {
+ if (Split[itr].empty())
+ {
+ continue;
+ }
+
+ a_FireworkItem.m_FadeColours.push_back(atoi(Split[itr].c_str()));
+ }
+}
+
+
+
+
+
+int cFireworkItem::GetVanillaColourCodeFromDye(short a_DyeMeta)
+{
+ /*
+ Colours are supposed to be calculated via: R << 16 + G << 8 + B
+ However, the RGB values fireworks use aren't the same as the ones for dyes (the ones listed in the MC Wiki)
+ Therefore, here is a list of numbers gotten via the Protocol Proxy
+ */
+
+ switch (a_DyeMeta)
+ {
+ case E_META_DYE_BLACK: return 0x1E1B1B;
+ case E_META_DYE_RED: return 0xB3312C;
+ case E_META_DYE_GREEN: return 0x3B511A;
+ case E_META_DYE_BROWN: return 0x51301A;
+ case E_META_DYE_BLUE: return 0x253192;
+ case E_META_DYE_PURPLE: return 0x7B2FBE;
+ case E_META_DYE_CYAN: return 0x287697;
+ case E_META_DYE_LIGHTGRAY: return 0xABABAB;
+ case E_META_DYE_GRAY: return 0x434343;
+ case E_META_DYE_PINK: return 0xD88198;
+ case E_META_DYE_LIGHTGREEN: return 0x41CD34;
+ case E_META_DYE_YELLOW: return 0xDECF2A;
+ case E_META_DYE_LIGHTBLUE: return 0x6689D3;
+ case E_META_DYE_MAGENTA: return 0xC354CD;
+ case E_META_DYE_ORANGE: return 0xEB8844;
+ case E_META_DYE_WHITE: return 0xF0F0F0;
+ default: ASSERT(!"Unhandled dye meta whilst trying to get colour code for fireworks!"); return 0;
+ }
+}
diff --git a/src/WorldStorage/FireworksSerializer.h b/src/WorldStorage/FireworksSerializer.h
new file mode 100644
index 000000000..5b87bafdb
--- /dev/null
+++ b/src/WorldStorage/FireworksSerializer.h
@@ -0,0 +1,92 @@
+
+// FireworksSerializer.h
+
+// Declares the cFireworkItem class representing a firework or firework star
+
+
+
+
+
+#pragma once
+
+#include "Defines.h"
+
+class cFastNBTWriter;
+class cParsedNBT;
+
+
+
+
+
+class cFireworkItem
+{
+public:
+ cFireworkItem(void) :
+ m_HasFlicker(false),
+ m_HasTrail(false),
+ m_Type(0),
+ m_FlightTimeInTicks(0)
+ {
+ }
+
+ inline void CopyFrom(const cFireworkItem & a_Item)
+ {
+ m_FlightTimeInTicks = a_Item.m_FlightTimeInTicks;
+ m_HasFlicker = a_Item.m_HasFlicker;
+ m_HasTrail = a_Item.m_HasTrail;
+ m_Type = a_Item.m_Type;
+ m_Colours = a_Item.m_Colours;
+ m_FadeColours = a_Item.m_FadeColours;
+ }
+
+ inline void EmptyData(void)
+ {
+ m_FlightTimeInTicks = 0;
+ m_HasFlicker = false;
+ m_Type = 0;
+ m_HasTrail = false;
+ m_Colours.clear();
+ m_FadeColours.clear();
+ }
+
+ inline bool IsEqualTo(const cFireworkItem & a_Item) const
+ {
+ return
+ (
+ (m_FlightTimeInTicks == a_Item.m_FlightTimeInTicks) &&
+ (m_HasFlicker == a_Item.m_HasFlicker) &&
+ (m_HasTrail == a_Item.m_HasTrail) &&
+ (m_Type == a_Item.m_Type) &&
+ (m_Colours == a_Item.m_Colours) &&
+ (m_FadeColours == a_Item.m_FadeColours)
+ );
+ }
+
+ /** Writes firework NBT data to a Writer object */
+ static void WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type);
+
+ /** Reads NBT data from a NBT object and populates a FireworkItem with it */
+ static void ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type);
+
+ /** Converts the firework's vector of colours into a string of values separated by a semicolon */
+ static AString ColoursToString(const cFireworkItem & a_FireworkItem);
+
+ /** Parses a string containing encoded firework colours and populates a FireworkItem with it */
+ static void ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
+
+ /** Converts the firework's vector of fade colours into a string of values separated by a semicolon */
+ static AString FadeColoursToString(const cFireworkItem & a_FireworkItem);
+
+ /** Parses a string containing encoded firework fade colours and populates a FireworkItem with it */
+ static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
+
+ /** Returns a colour code for fireworks used by the network code */
+ static int GetVanillaColourCodeFromDye(short a_DyeMeta);
+
+ bool m_HasFlicker;
+ bool m_HasTrail;
+ NIBBLETYPE m_Type;
+ short m_FlightTimeInTicks;
+ std::vector<int> m_Colours;
+ std::vector<int> m_FadeColours;
+}; \ No newline at end of file
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 6d0e29958..4cf3c62d7 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -28,6 +28,7 @@
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
+#include "../Entities/TNTEntity.h"
#include "../Mobs/Monster.h"
#include "../Mobs/Bat.h"
@@ -91,11 +92,19 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin
}
// Write the enchantments:
- if (!a_Item.m_Enchantments.IsEmpty())
+ if (!a_Item.m_Enchantments.IsEmpty() || ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)))
{
- const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
m_Writer.BeginCompound("tag");
- EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName);
+ if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, m_Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
+
+ if (!a_Item.m_Enchantments.IsEmpty())
+ {
+ const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
+ EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName);
+ }
m_Writer.EndCompound();
}
@@ -583,6 +592,18 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
+void cNBTChunkSerializer::AddTNTEntity(cTNTEntity * a_TNT)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_TNT, "PrimedTnt");
+ m_Writer.AddByte("Fuse", (unsigned char)a_TNT->GetFuseTicks());
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{
m_Writer.BeginList("Items", TAG_Compound);
@@ -662,7 +683,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
- case cEntity::etTNT: /* TODO */ break;
+ case cEntity::etTNT: AddTNTEntity ((cTNTEntity *) a_Entity); break;
case cEntity::etExpOrb: /* TODO */ break;
case cEntity::etItemFrame: /* TODO */ break;
case cEntity::etPainting: /* TODO */ break;
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 8a9e18413..3b486d2bc 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -41,6 +41,7 @@ class cMonster;
class cPickup;
class cItemGrid;
class cProjectileEntity;
+class cTNTEntity;
@@ -107,6 +108,7 @@ protected:
void AddMonsterEntity (cMonster * a_Monster);
void AddPickupEntity (cPickup * a_Pickup);
void AddProjectileEntity (cProjectileEntity * a_Projectile);
+ void AddTNTEntity (cTNTEntity * a_TNT);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 680f2458f..eb159f28d 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -36,6 +36,7 @@
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
+#include "../Entities/TNTEntity.h"
@@ -663,6 +664,12 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
{
EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag);
}
+
+ int FireworksTag = a_NBT.FindChildByName(TagTag, ((a_Item.m_ItemType == E_ITEM_FIREWORK_STAR) ? "Fireworks" : "Explosion"));
+ if (EnchTag > 0)
+ {
+ cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, a_NBT, FireworksTag, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
return true;
}
@@ -1231,6 +1238,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadPigZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
+ else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
+ {
+ LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
// TODO: other entities
}
@@ -2167,6 +2178,28 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT
+void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
+ if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
+ // Load Fuse Ticks:
+ int FuseTicks = a_NBT.FindChildByName(a_TagIdx, "Fuse");
+ if (FuseTicks > 0)
+ {
+ TNT->SetFuseTicks((int) a_NBT.GetByte(FuseTicks));
+ }
+
+ a_Entities.push_back(TNT.release());
+}
+
+
+
+
+
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
{
double Pos[3];
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index b26345b13..fe93d16c3 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -192,6 +192,7 @@ protected:
void LoadWolfFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPigZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadTNTFromNBT (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);