summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Bindings/AllToLua.pkg1
-rw-r--r--src/BlockID.h2
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/Chunk.cpp32
-rw-r--r--src/Chunk.h8
-rw-r--r--src/ChunkMap.cpp61
-rw-r--r--src/ChunkMap.h9
-rw-r--r--src/ClientHandle.cpp8
-rw-r--r--src/ClientHandle.h2
-rw-r--r--src/Entities/Entity.h2
-rw-r--r--src/Entities/Painting.cpp43
-rw-r--r--src/Entities/Painting.h42
-rw-r--r--src/ForEachChunkProvider.h27
-rw-r--r--src/Items/ItemHandler.cpp6
-rw-r--r--src/Items/ItemPainting.h98
-rw-r--r--src/Protocol/Protocol.h2
-rw-r--r--src/Protocol/Protocol125.h1
-rw-r--r--src/Protocol/Protocol17x.cpp15
-rw-r--r--src/Protocol/Protocol17x.h1
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp8
-rw-r--r--src/Protocol/ProtocolRecognizer.h1
-rw-r--r--src/World.cpp41
-rw-r--r--src/World.h32
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp1
24 files changed, 433 insertions, 11 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 6c295102f..1f08c66dc 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -34,6 +34,7 @@ $cfile "../Entities/Entity.h"
$cfile "../Entities/Floater.h"
$cfile "../Entities/Pawn.h"
$cfile "../Entities/Player.h"
+$cfile "../Entities/Painting.h"
$cfile "../Entities/Pickup.h"
$cfile "../Entities/ProjectileEntity.h"
$cfile "../Entities/TNTEntity.h"
diff --git a/src/BlockID.h b/src/BlockID.h
index d5b3da672..740c5fc90 100644
--- a/src/BlockID.h
+++ b/src/BlockID.h
@@ -266,7 +266,7 @@ enum ENUM_ITEM_ID
E_ITEM_FLINT = 318,
E_ITEM_RAW_PORKCHOP = 319,
E_ITEM_COOKED_PORKCHOP = 320,
- E_ITEM_PAINTINGS = 321,
+ E_ITEM_PAINTING = 321,
E_ITEM_GOLDEN_APPLE = 322,
E_ITEM_SIGN = 323,
E_ITEM_WOODEN_DOOR = 324,
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6ba952f92..16bdad14e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -52,6 +52,7 @@ if (NOT MSVC)
Entities/Entity.h
Entities/Floater.h
Entities/Pawn.h
+ Entities/Painting.h
Entities/Pickup.h
Entities/Player.h
Entities/ProjectileEntity.h
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 3028d24d0..0587beb9c 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -1652,6 +1652,38 @@ void cChunk::UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z)
+void cChunk::SetBiomeAt(int a_RelX, int a_RelZ, EMCSBiome a_Biome)
+{
+ cChunkDef::SetBiome(m_BiomeMap, a_RelX, a_RelZ, a_Biome);
+ MarkDirty();
+}
+
+
+
+
+
+void cChunk::SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_MaxRelZ, EMCSBiome a_Biome)
+{
+ for (int z = a_MinRelZ; z <= a_MaxRelZ; z++)
+ {
+ for (int x = a_MinRelX; x <= a_MaxRelX; x++)
+ {
+ cChunkDef::SetBiome(m_BiomeMap, x, z, a_Biome);
+ }
+ }
+ MarkDirty();
+
+ // Re-send the chunk to all clients:
+ for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr)
+ {
+ m_World->ForceSendChunkTo(m_PosX, m_PosZ, (*itr));
+ } // for itr - m_LoadedByClient[]
+}
+
+
+
+
+
void cChunk::CollectPickupsByPlayer(cPlayer * a_Player)
{
double PosX = a_Player->GetPosX();
diff --git a/src/Chunk.h b/src/Chunk.h
index 696690068..682ec6170 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -175,6 +175,14 @@ public:
EMCSBiome GetBiomeAt(int a_RelX, int a_RelZ) const {return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); }
+ /** Sets the biome at the specified relative coords.
+ Doesn't resend the chunk to clients. */
+ void SetBiomeAt(int a_RelX, int a_RelZ, EMCSBiome a_Biome);
+
+ /** Sets the biome in the specified relative coords area. All the coords are inclusive.
+ Sends the chunk to all relevant clients. */
+ void SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_MaxRelZ, EMCSBiome a_Biome);
+
void CollectPickupsByPlayer(cPlayer * a_Player);
/** Sets the sign text. Returns true if successful. Also sends update packets to all clients in the chunk */
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 0c5a8d9b9..01195e8bc 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -1390,10 +1390,10 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks)
EMCSBiome cChunkMap::GetBiomeAt (int a_BlockX, int a_BlockZ)
{
int ChunkX, ChunkZ, X = a_BlockX, Y = 0, Z = a_BlockZ;
- cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ );
+ cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
- cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ );
+ cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk != NULL) && Chunk->IsValid())
{
return Chunk->GetBiomeAt(X, Z);
@@ -1408,6 +1408,63 @@ EMCSBiome cChunkMap::GetBiomeAt (int a_BlockX, int a_BlockZ)
+bool cChunkMap::SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome)
+{
+ int ChunkX, ChunkZ, X = a_BlockX, Y = 0, Z = a_BlockZ;
+ cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
+
+ cCSLock Lock(m_CSLayers);
+ cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ);
+ if ((Chunk != NULL) && Chunk->IsValid())
+ {
+ Chunk->SetBiomeAt(X, Z, a_Biome);
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
+bool cChunkMap::SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome)
+{
+ // Translate coords to relative:
+ int Y = 0;
+ int MinChunkX, MinChunkZ, MinX = a_MinX, MinZ = a_MinZ;
+ int MaxChunkX, MaxChunkZ, MaxX = a_MaxX, MaxZ = a_MaxZ;
+ cChunkDef::AbsoluteToRelative(MinX, Y, MinZ, MinChunkX, MinChunkZ);
+ cChunkDef::AbsoluteToRelative(MaxX, Y, MaxZ, MaxChunkX, MaxChunkZ);
+
+ // Go through all chunks, set:
+ bool res = true;
+ cCSLock Lock(m_CSLayers);
+ for (int x = MinChunkX; x <= MaxChunkX; x++)
+ {
+ int MinRelX = (x == MinChunkX) ? MinX : 0;
+ int MaxRelX = (x == MaxChunkX) ? MaxX : cChunkDef::Width - 1;
+ for (int z = MinChunkZ; z <= MaxChunkZ; z++)
+ {
+ int MinRelZ = (z == MinChunkZ) ? MinZ : 0;
+ int MaxRelZ = (z == MaxChunkZ) ? MaxZ : cChunkDef::Width - 1;
+ cChunkPtr Chunk = GetChunkNoLoad(x, ZERO_CHUNK_Y, z);
+ if ((Chunk != NULL) && Chunk->IsValid())
+ {
+ Chunk->SetAreaBiome(MinRelX, MaxRelX, MinRelZ, MaxRelZ, a_Biome);
+ }
+ else
+ {
+ res = false;
+ }
+ } // for z
+ } // for x
+ return res;
+}
+
+
+
+
+
bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
{
bool res = true;
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index d713d0cf5..9f0dd087e 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -159,8 +159,17 @@ public:
/** Special function used for growing trees, replaces only blocks that tree may overwrite */
void ReplaceTreeBlocks(const sSetBlockVector & a_Blocks);
+ /** Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value */
EMCSBiome GetBiomeAt (int a_BlockX, int a_BlockZ);
+ /** Sets the biome at the specified coords. Returns true if successful, false if not (chunk not loaded).
+ Doesn't resend the chunk to clients. */
+ bool SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome);
+
+ /** Sets the biome at the area. Returns true if successful, false if any subarea failed (chunk not loaded).
+ (Re)sends the chunks to their relevant clients if successful. */
+ bool SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome);
+
/** Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. */
bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure);
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index c91a0c01b..84286fc41 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -2091,6 +2091,14 @@ void cClientHandle::SendPickupSpawn(const cPickup & a_Pickup)
+void cClientHandle::SendPaintingSpawn(const cPainting & a_Painting)
+{
+ m_Protocol->SendPaintingSpawn(a_Painting);
+}
+
+
+
+
void cClientHandle::SendEntityAnimation(const cEntity & a_Entity, char a_Animation)
{
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 5faa94004..aefca7233 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -27,6 +27,7 @@ class cInventory;
class cMonster;
class cPawn;
class cExpOrb;
+class cPainting;
class cPickup;
class cPlayer;
class cProtocol;
@@ -111,6 +112,7 @@ public:
void SendGameMode (eGameMode a_GameMode);
void SendHealth (void);
void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item);
+ void SendPaintingSpawn (const cPainting & a_Painting);
void SendPickupSpawn (const cPickup & a_Pickup);
void SendEntityAnimation (const cEntity & a_Entity, char a_Animation);
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);
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 79150ee51..b3b1cef83 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -82,6 +82,7 @@ public:
etExpOrb,
etFloater,
etItemFrame,
+ etPainting,
// Common variations
etMob = etMonster, // DEPRECATED, use etMonster instead!
@@ -141,6 +142,7 @@ public:
bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); }
bool IsFloater (void) const { return (m_EntityType == etFloater); }
bool IsItemFrame (void) const { return (m_EntityType == etItemFrame); }
+ bool IsPainting (void) const { return (m_EntityType == etPainting); }
/// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true)
virtual bool IsA(const char * a_ClassName) const;
diff --git a/src/Entities/Painting.cpp b/src/Entities/Painting.cpp
new file mode 100644
index 000000000..b98c1e67a
--- /dev/null
+++ b/src/Entities/Painting.cpp
@@ -0,0 +1,43 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Painting.h"
+#include "ClientHandle.h"
+#include "Player.h"
+
+
+
+
+
+cPainting::cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z)
+ : cEntity(etPainting, a_X, a_Y, a_Z, 1, 1),
+ m_Name(a_Name),
+ m_Direction(a_Direction)
+{
+}
+
+
+
+
+
+
+void cPainting::SpawnOn(cClientHandle & a_Client)
+{
+ a_Client.SendPaintingSpawn(*this);
+}
+
+
+
+
+
+void cPainting::GetDrops(cItems & a_Items, cEntity * a_Killer)
+{
+ if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative())
+ {
+ a_Items.push_back(cItem(E_ITEM_PAINTING));
+ }
+}
+
+
+
+
diff --git a/src/Entities/Painting.h b/src/Entities/Painting.h
new file mode 100644
index 000000000..95afbed1e
--- /dev/null
+++ b/src/Entities/Painting.h
@@ -0,0 +1,42 @@
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+class cPainting :
+ public cEntity
+{
+ // tolua_end
+ typedef cEntity super;
+
+public:
+ CLASS_PROTODEF(cPainting);
+
+ cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z);
+ const AString & GetName(void) const { return m_Name; } // tolua_export
+ int GetDirection(void) const { return m_Direction; } // tolua_export
+
+private:
+
+ virtual void SpawnOn(cClientHandle & a_Client) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
+ virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
+ virtual void KilledBy(cEntity * a_Killer) override
+ {
+ super::KilledBy(a_Killer);
+ Destroy();
+ }
+
+ AString m_Name;
+ int m_Direction;
+
+}; // tolua_export
+
+
+
+
diff --git a/src/ForEachChunkProvider.h b/src/ForEachChunkProvider.h
index 70cd2196a..6017173ee 100644
--- a/src/ForEachChunkProvider.h
+++ b/src/ForEachChunkProvider.h
@@ -1,14 +1,39 @@
+// ForEachChunkProvider.h
+
+// Declares the cForEachChunkProvider class which acts as an interface for classes that provide a ForEachChunkInRect() function
+// Primarily serves as a decoupling between cBlockArea and cWorld
+
+
+
+
+
#pragma once
-class cChunkDataCallback;
+
+
+// fwd:
+class cChunkDataCallback;
class cBlockArea;
+
+
+
+
class cForEachChunkProvider
{
public:
+ /** Calls the callback for each chunk in the specified range. */
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback) = 0;
+ /** Writes the block area into the specified coords.
+ Returns true if all chunks have been processed.
+ a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together.
+ */
virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) = 0;
};
+
+
+
+
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index da1cd768d..945f84b9c 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -27,6 +27,7 @@
#include "ItemLighter.h"
#include "ItemMinecart.h"
#include "ItemNetherWart.h"
+#include "ItemPainting.h"
#include "ItemPickaxe.h"
#include "ItemThrowable.h"
#include "ItemRedstoneDust.h"
@@ -108,6 +109,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType);
case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType);
+ case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType);
case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType);
case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType);
case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType);
@@ -307,7 +309,7 @@ char cItemHandler::GetMaxStackSize(void)
case E_ITEM_BOWL: return 64;
case E_ITEM_BREAD: return 64;
case E_ITEM_BREWING_STAND: return 64;
- case E_ITEM_BUCKET: return 1; // TODO: change this to 16 when turning compatibility to 1.3
+ case E_ITEM_BUCKET: return 16;
case E_ITEM_CARROT: return 64;
case E_ITEM_CAULDRON: return 64;
case E_ITEM_CLAY: return 64;
@@ -352,7 +354,7 @@ char cItemHandler::GetMaxStackSize(void)
case E_ITEM_MELON_SLICE: return 64;
case E_ITEM_NETHER_BRICK: return 64;
case E_ITEM_NETHER_WART: return 64;
- case E_ITEM_PAINTINGS: return 64;
+ case E_ITEM_PAINTING: return 64;
case E_ITEM_PAPER: return 64;
case E_ITEM_POISONOUS_POTATO: return 64;
case E_ITEM_POTATO: return 64;
diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h
new file mode 100644
index 000000000..b85098221
--- /dev/null
+++ b/src/Items/ItemPainting.h
@@ -0,0 +1,98 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+#include "../Entities/Painting.h"
+
+
+
+
+
+class cItemPaintingHandler :
+ public cItemHandler
+{
+public:
+ cItemPaintingHandler(int a_ItemType)
+ : cItemHandler(a_ItemType)
+ {
+ }
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
+ {
+ if (a_Dir == BLOCK_FACE_NONE)
+ {
+ // Client sends this if clicked on top or bottom face
+ return false;
+ }
+
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free
+ BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again
+
+ if (Block == E_BLOCK_AIR)
+ {
+ int Dir = 0;
+
+ // The client uses different values for painting directions and block faces. Our constants are for the block faces, so we convert them here to painting faces
+ switch (a_Dir)
+ {
+ case BLOCK_FACE_ZP: break; // Initialised to zero
+ case BLOCK_FACE_ZM: Dir = 2; break;
+ case BLOCK_FACE_XM: Dir = 1; break;
+ case BLOCK_FACE_XP: Dir = 3; break;
+ default: ASSERT(!"Unhandled block face when trying spawn painting!"); return false;
+ }
+
+ static const struct // Define all the possible painting titles
+ {
+ AString Title;
+ } gPaintingTitlesList[] =
+ {
+ { "Kebab" },
+ { "Aztec" },
+ { "Alban" },
+ { "Aztec2" },
+ { "Bomb" },
+ { "Plant" },
+ { "Wasteland" },
+ { "Wanderer" },
+ { "Graham" },
+ { "Pool" },
+ { "Courbet" },
+ { "Sunset" },
+ { "Sea" },
+ { "Creebet" },
+ { "Match" },
+ { "Bust" },
+ { "Stage" },
+ { "Void" },
+ { "SkullAndRoses" },
+ { "Wither" },
+ { "Fighters" },
+ { "Skeleton" },
+ { "DonkeyKong" },
+ { "Pointer" },
+ { "Pigscene" },
+ { "BurningSkull" }
+ };
+
+ cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, Dir, a_BlockX, a_BlockY, a_BlockZ);
+ Painting->Initialize(a_World);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+
+ return true;
+
+ }
+ return false;
+ }
+};
+
+
+
+
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index f5b9fd403..46b627254 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -24,6 +24,7 @@ class cWindow;
class cInventory;
class cPawn;
class cPickup;
+class cPainting;
class cWorld;
class cMonster;
class cChunkDataSerializer;
@@ -81,6 +82,7 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0;
virtual void SendKeepAlive (int a_PingID) = 0;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0;
+ virtual void SendPaintingSpawn (const cPainting & a_Painting) = 0;
virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0;
virtual void SendPlayerAbilities (void) = 0;
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0;
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index 1a3209333..54551ea5f 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -56,6 +56,7 @@ public:
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
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 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;
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 3d6a8f807..0c569c07c 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -21,6 +21,7 @@ Implements the 1.7.x protocol classes:
#include "../Entities/ExpOrb.h"
#include "../Entities/Minecart.h"
#include "../Entities/FallingBlock.h"
+#include "../Entities/Painting.h"
#include "../Entities/Pickup.h"
#include "../Entities/Player.h"
#include "../Entities/ItemFrame.h"
@@ -570,6 +571,20 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
+void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting)
+{
+ cPacketizer Pkt(*this, 0x10); // Spawn Painting packet
+ Pkt.WriteVarInt(a_Painting.GetUniqueID());
+ Pkt.WriteString(a_Painting.GetName().c_str());
+ Pkt.WriteInt((int)a_Painting.GetPosX());
+ Pkt.WriteInt((int)a_Painting.GetPosY());
+ Pkt.WriteInt((int)a_Painting.GetPosZ());
+ Pkt.WriteInt(a_Painting.GetDirection());
+}
+
+
+
+
void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
{
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index d19be0f05..ae3577867 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -87,6 +87,7 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
+ virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override;
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 6e51ee9cd..b658dc9db 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -405,6 +405,14 @@ void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, flo
+void cProtocolRecognizer::SendPaintingSpawn(const cPainting & a_Painting)
+{
+ m_Protocol->SendPaintingSpawn(a_Painting);
+}
+
+
+
+
void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup)
{
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index 800163be6..abbb22827 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -91,6 +91,7 @@ public:
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
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 SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override;
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
diff --git a/src/World.cpp b/src/World.cpp
index d67ad36d1..e57675c44 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1487,6 +1487,37 @@ EMCSBiome cWorld::GetBiomeAt (int a_BlockX, int a_BlockZ)
+bool cWorld::SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome)
+{
+ return m_ChunkMap->SetBiomeAt(a_BlockX, a_BlockZ, a_Biome);
+}
+
+
+
+
+
+bool cWorld::SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome)
+{
+ return m_ChunkMap->SetAreaBiome(a_MinX, a_MaxX, a_MinZ, a_MaxZ, a_Biome);
+}
+
+
+
+
+
+bool cWorld::SetAreaBiome(const cCuboid & a_Area, EMCSBiome a_Biome)
+{
+ return SetAreaBiome(
+ std::min(a_Area.p1.x, a_Area.p2.x), std::max(a_Area.p1.x, a_Area.p2.x),
+ std::min(a_Area.p1.z, a_Area.p2.z), std::max(a_Area.p1.z, a_Area.p2.z),
+ a_Biome
+ );
+}
+
+
+
+
+
void cWorld::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
m_ChunkMap->SetBlock(*this, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
@@ -2490,6 +2521,16 @@ void cWorld::SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client)
+void cWorld::ForceSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client)
+{
+ a_Client->AddWantedChunk(a_ChunkX, a_ChunkZ);
+ m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Client);
+}
+
+
+
+
+
void cWorld::RemoveClientFromChunkSender(cClientHandle * a_Client)
{
m_ChunkSender.RemoveClient(a_Client);
diff --git a/src/World.h b/src/World.h
index 97358b88a..d79de3b87 100644
--- a/src/World.h
+++ b/src/World.h
@@ -47,6 +47,7 @@ class cFurnaceEntity;
class cNoteEntity;
class cMobCensus;
class cCompositeChat;
+class cCuboid;
typedef std::list< cPlayer * > cPlayerList;
@@ -64,7 +65,10 @@ typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
// tolua_begin
-class cWorld : public cForEachChunkProvider, public cWorldInterface, public cBroadcastInterface
+class cWorld :
+ public cForEachChunkProvider,
+ public cWorldInterface,
+ public cBroadcastInterface
{
public:
@@ -303,9 +307,14 @@ public:
/** Removes the client from all chunks it is present in */
void RemoveClientFromChunks(cClientHandle * a_Client);
- /** Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted) */
+ /** Sends the chunk to the client specified, if the client doesn't have the chunk yet.
+ If chunk not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid + lighted). */
void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+ /** Sends the chunk to the client specified, even if the client already has the chunk.
+ If the chunk's not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid + lighted). */
+ void ForceSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
/** Removes client from ChunkSender's queue of chunks to be sent */
void RemoveClientFromChunkSender(cClientHandle * a_Client);
@@ -401,15 +410,15 @@ public:
Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too.
a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together.
*/
- virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
+ virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) override;
// tolua_begin
/** Spawns item pickups for each item in the list. May compress pickups if too many entities: */
- virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false);
+ virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false); // override; cannot specify it here due to tolua
/** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: */
- virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false);
+ virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false); // override; cannot specify it here due to tolua
/** Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. */
int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta);
@@ -546,6 +555,19 @@ public:
/** Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value */
EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ);
+
+ /** Sets the biome at the specified coords. Returns true if successful, false if not (chunk not loaded).
+ Doesn't resend the chunk to clients, use ForceSendChunkTo() for that. */
+ bool SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome);
+
+ /** Sets the biome at the area. Returns true if successful, false if any subarea failed (chunk not loaded).
+ (Re)sends the chunks to their relevant clients if successful. */
+ bool SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome);
+
+ /** Sets the biome at the area. Returns true if successful, false if any subarea failed (chunk not loaded).
+ (Re)sends the chunks to their relevant clients if successful.
+ The cuboid needn't be sorted. */
+ bool SetAreaBiome(const cCuboid & a_Area, EMCSBiome a_Biome);
/** Returns the name of the world */
const AString & GetName(void) const { return m_WorldName; }
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 4f1e88b21..c7aaa2633 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -628,6 +628,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
case cEntity::etTNT: /* TODO */ break;
case cEntity::etExpOrb: /* TODO */ break;
case cEntity::etItemFrame: /* TODO */ break;
+ case cEntity::etPainting: /* TODO */ break;
case cEntity::etPlayer: return; // Players aren't saved into the world
default:
{