summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua7
-rw-r--r--src/Bindings/LuaState.cpp41
-rw-r--r--src/Bindings/LuaState.h6
-rw-r--r--src/Bindings/ManualBindings.cpp58
-rw-r--r--src/Broadcaster.cpp47
-rw-r--r--src/Broadcaster.h20
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Chunk.h6
-rw-r--r--src/ChunkMap.cpp22
-rw-r--r--src/ChunkMap.h3
-rw-r--r--src/ClientHandle.cpp9
-rw-r--r--src/ClientHandle.h2
-rw-r--r--src/Entities/Floater.cpp6
-rw-r--r--src/Mobs/Path.cpp2
-rw-r--r--src/Mobs/Wolf.cpp5
-rw-r--r--src/Protocol/Protocol.h3
-rw-r--r--src/Protocol/Protocol17x.cpp10
-rw-r--r--src/Protocol/Protocol17x.h1
-rw-r--r--src/Protocol/Protocol18x.cpp44
-rw-r--r--src/Protocol/Protocol18x.h1
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp11
-rw-r--r--src/Protocol/ProtocolRecognizer.h1
-rw-r--r--src/World.cpp24
-rw-r--r--src/World.h7
24 files changed, 314 insertions, 24 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 7c0a8e818..79340434d 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -8,7 +8,6 @@
g_APIDesc =
{
Classes =
- {
--[[
-- What the APIDump plugin understands / how to document stuff:
ExampleClassName =
@@ -2046,8 +2045,8 @@ a_Player:OpenWindow(Window);
BroadcastChatLeave = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtLeave. Use for players leaving the server." },
BroadcastChatSuccess = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtSuccess. Use for success messages." },
BroadcastChatWarning = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtWarning. Use for concerning events, such as plugin reload etc." },
- CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil.<br/><br/><b>NOTE</b>This function is currently unsafe, do not use!" },
- FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "", Notes = "Calls the given callback function for all players with names partially (or fully) matching the name string provided." },
+ CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil.<br><br><b>NOTE</b>This function is currently unsafe, do not use!" },
+ FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "bool", Notes = "Calls the given callback function for the player with the name best matching the name string provided.<br>This function is case-insensitive and will match partial names.<br>Returns false if player not found or there is ambiguity, true otherwise. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}})</pre>" },
DoWithPlayerByUUID = { Params = "PlayerUUID, CallbackFunction", Return = "bool", Notes = "If there is the player with the uuid, calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}})</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." },
ForEachPlayer = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each player. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|cPlayer}})</pre>" },
ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cWorld|cWorld}})</pre>" },
@@ -2331,7 +2330,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
{ Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "", Notes = "Sets the block at the specified coords, without waking up the simulators or replacing the block entities for the previous block type. Do not use if the block being replaced has a block entity tied to it!" },
{ Params = "{{Vector3i|BlockCoords}}, BlockType, BlockMeta", Return = "", Notes = "Sets the block at the specified coords, without waking up the simulators or replacing the block entities for the previous block type. Do not use if the block being replaced has a block entity tied to it!" },
},
- FindAndDoWithPlayer = { Params = "PlayerNameHint, CallbackFunction", Return = "bool", Notes = "If there is a player of a name similar to the specified name (weighted-match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}})</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found. Note that the name matching is very loose, so it is a good idea to check the player name in the callback function." },
+ FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "bool", Notes = "Calls the given callback function for the player with the name best matching the name string provided.<br>This function is case-insensitive and will match partial names.<br>Returns false if player not found or there is ambiguity, true otherwise. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}})</pre>" },
ForEachBlockEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each block entity in the chunk. Returns true if all block entities in the chunk have been processed (including when there are zero block entities), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}})</pre> The callback should return false or no value to continue with the next block entity, or true to abort the enumeration. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
ForEachChestInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each chest in the chunk. Returns true if all chests in the chunk have been processed (including when there are zero chests), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}})</pre> The callback should return false or no value to continue with the next chest, or true to abort the enumeration." },
ForEachEntity = { Params = "CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each entity in the loaded world. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}})</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index ed31e678f..f574dbe26 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -1133,6 +1133,23 @@ void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal)
+void cLuaState::GetStackValue(int a_StackPos, pClientHandle & a_ReturnedVal)
+{
+ if (lua_isnil(m_LuaState, a_StackPos))
+ {
+ a_ReturnedVal = nullptr;
+ return;
+ }
+ tolua_Error err;
+ if (tolua_isusertype(m_LuaState, a_StackPos, "cClientHandle", false, &err))
+ {
+ a_ReturnedVal = *(reinterpret_cast<cClientHandle **>(lua_touserdata(m_LuaState, a_StackPos)));
+ }
+}
+
+
+
+
bool cLuaState::CallFunction(int a_NumResults)
{
ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first
@@ -1415,6 +1432,30 @@ bool cLuaState::CheckParamEnd(int a_Param)
+bool cLuaState::IsParamUserType(int a_Param, AString a_UserType)
+{
+ ASSERT(IsValid());
+
+ tolua_Error tolua_err;
+ return tolua_isusertype(m_LuaState, a_Param, a_UserType.c_str(), 0, &tolua_err);
+}
+
+
+
+
+
+bool cLuaState::IsParamNumber(int a_Param)
+{
+ ASSERT(IsValid());
+
+ tolua_Error tolua_err;
+ return tolua_isnumber(m_LuaState, a_Param, 0, &tolua_err);
+}
+
+
+
+
+
bool cLuaState::ReportErrors(int a_Status)
{
return ReportErrors(m_LuaState, a_Status);
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index 6bedbf5ec..3f2e828f3 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -76,6 +76,7 @@ typedef cPluginManager * pPluginManager;
typedef cRoot * pRoot;
typedef cScoreboard * pScoreboard;
typedef cWorld * pWorld;
+typedef cClientHandle * pClientHandle;
@@ -254,6 +255,7 @@ public:
void GetStackValue(int a_StackPos, int & a_Value);
void GetStackValue(int a_StackPos, pBlockArea & a_Value);
void GetStackValue(int a_StackPos, pBoundingBox & a_Value);
+ void GetStackValue(int a_StackPos, pClientHandle & a_Value);
void GetStackValue(int a_StackPos, pMapManager & a_Value);
void GetStackValue(int a_StackPos, pPluginManager & a_Value);
void GetStackValue(int a_StackPos, pRoot & a_Value);
@@ -307,6 +309,10 @@ public:
/** Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) */
bool CheckParamEnd(int a_Param);
+ bool IsParamUserType(int a_Param, AString a_UserType);
+
+ bool IsParamNumber(int a_Param);
+
/** If the status is nonzero, prints the text on the top of Lua stack and returns true */
bool ReportErrors(int status);
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index f25800d5f..2fbff11d3 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -32,9 +32,10 @@
#include "../WorldStorage/SchematicFileSerializer.h"
#include "../CompositeChat.h"
#include "../StringCompression.h"
+#include "../Broadcaster.h"
-
+#include <array>
// Better error reporting for Lua
@@ -2009,6 +2010,60 @@ static int tolua_cPluginManager_FindPlugins(lua_State * tolua_S)
+static int tolua_cWorld_BroadcastParticleEffect(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cWorld") ||
+ !L.CheckParamString (2) ||
+ !L.CheckParamNumber (3, 10)
+ )
+ {
+ return 0;
+ }
+
+ cPluginLua * Plugin = GetLuaPlugin(tolua_S);
+ if (Plugin == nullptr)
+ {
+ return 0;
+ }
+
+ // Read the params:
+ cWorld * World = nullptr;
+ AString Name;
+ double PosX, PosY, PosZ, OffX, OffY, OffZ;
+ double ParticleData;
+ int ParticleAmmount;
+ L.GetStackValues(1, World, Name, PosX, PosY, PosZ, OffX, OffY, OffZ, ParticleData, ParticleAmmount);
+ if (World == nullptr)
+ {
+ LOGWARNING("World:BroadcastParticleEffect(): invalid world parameter");
+ L.LogStackTrace();
+ return 0;
+ }
+
+ std::array<int, 2> data;
+
+ for (int i = 0; (i < 2) && L.IsParamNumber(11 + i); i++)
+ {
+ L.GetStackValue(11 + i, data[i]);
+ }
+
+ cClientHandle * Exclude = nullptr;
+
+ if (L.IsParamUserType(11, "cClientHandle"))
+ {
+ L.GetStackValue(11, Exclude);
+ }
+ World->GetBroadcaster().BroadcastParticleEffect(Name, Vector3f(PosX, PosY, PosZ), Vector3f(OffX, OffY, OffZ), ParticleData, ParticleAmmount, Exclude);
+
+ return 0;
+}
+
+
+
+
+
static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
{
/* Function signature:
@@ -3792,6 +3847,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cWorld");
+ tolua_function(tolua_S, "BroadcastParticleEffect", tolua_cWorld_BroadcastParticleEffect);
tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay);
tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>);
tolua_function(tolua_S, "DoWithBeaconAt", tolua_DoWithXYZ<cWorld, cBeaconEntity, &cWorld::DoWithBeaconAt>);
diff --git a/src/Broadcaster.cpp b/src/Broadcaster.cpp
new file mode 100644
index 000000000..7f2b65d09
--- /dev/null
+++ b/src/Broadcaster.cpp
@@ -0,0 +1,47 @@
+
+#include "Globals.h"
+#include "Broadcaster.h"
+#include "World.h"
+#include "Chunk.h"
+
+cBroadcaster::cBroadcaster(cWorld * a_World) :
+ m_World(a_World)
+{
+}
+
+
+void cBroadcaster::BroadcastParticleEffect(const AString & a_ParticleName, const Vector3f a_Src, const Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, cClientHandle * a_Exclude)
+{
+ m_World->DoWithChunkAt(a_Src,
+ [=](cChunk & a_Chunk) -> bool
+ {
+ for (auto&& client : a_Chunk.GetAllClients())
+ {
+ if (client == a_Exclude)
+ {
+ continue;
+ }
+ client->SendParticleEffect(a_ParticleName, a_Src.x, a_Src.y, a_Src.z, a_Offset.x, a_Offset.y, a_Offset.z, a_ParticleData, a_ParticleAmount);
+ };
+ return true;
+ });
+}
+
+
+void cBroadcaster::BroadcastParticleEffect(const AString & a_ParticleName, const Vector3f a_Src, const Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data, cClientHandle * a_Exclude)
+{
+ m_World->DoWithChunkAt(a_Src,
+ [=](cChunk & a_Chunk) -> bool
+ {
+ for (auto && client : a_Chunk.GetAllClients())
+ {
+ if (client == a_Exclude)
+ {
+ continue;
+ }
+ client->SendParticleEffect(a_ParticleName, a_Src, a_Offset, a_ParticleData, a_ParticleAmount, a_Data);
+ };
+ return true;
+ });
+}
+
diff --git a/src/Broadcaster.h b/src/Broadcaster.h
new file mode 100644
index 000000000..27d35fe4d
--- /dev/null
+++ b/src/Broadcaster.h
@@ -0,0 +1,20 @@
+
+class cWorld;
+
+#include <array>
+
+class cBroadcaster
+{
+
+public:
+
+ cBroadcaster(cWorld * a_World);
+
+ void BroadcastParticleEffect(const AString & a_ParticleName, const Vector3f a_Src, const Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, cClientHandle * a_Exclude = nullptr);
+
+ void BroadcastParticleEffect(const AString & a_ParticleName, const Vector3f a_Src, const Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data, cClientHandle * a_Exclude = nullptr);
+
+private:
+ cWorld * m_World;
+
+};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e04e6311f..fd28f3787 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -18,6 +18,7 @@ SET (SRCS
BlockArea.cpp
BlockID.cpp
BlockInfo.cpp
+ Broadcaster.cpp
BoundingBox.cpp
ByteBuffer.cpp
ChatColor.cpp
@@ -77,6 +78,7 @@ SET (HDRS
BlockInServerPluginInterface.h
BlockInfo.h
BlockTracer.h
+ Broadcaster.h
BoundingBox.h
BuildInfo.h.cmake
ByteBuffer.h
diff --git a/src/Chunk.h b/src/Chunk.h
index e8c60a74b..58f6ba707 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -439,6 +439,9 @@ public:
as at least one requests is active the chunk will be ticked). */
void SetAlwaysTicked(bool a_AlwaysTicked);
+ // Makes a copy of the list
+ cClientHandleList GetAllClients(void) const {return m_LoadedByClient; }
+
private:
friend class cChunkMap;
@@ -530,9 +533,6 @@ private:
/** Wakes up each simulator for its specific blocks; through all the blocks in the chunk */
void WakeUpSimulators(void);
-
- // Makes a copy of the list
- cClientHandleList GetAllClients(void) const {return m_LoadedByClient; }
/** Sends m_PendingSendBlocks to all clients */
void BroadcastPendingBlockChanges(void);
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index b84b8dc3d..edff6baf1 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -791,6 +791,28 @@ bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callb
}
+bool cChunkMap::DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback)
+{
+ int ChunkX, ChunkZ;
+ cChunkDef::BlockToChunk(a_BlockPos.x, a_BlockPos.z, ChunkX, ChunkZ);
+ struct cCallBackWrapper : cChunkCallback
+ {
+ cCallBackWrapper(std::function<bool(cChunk &)> a_InnerCallback) :
+ m_Callback(a_InnerCallback)
+ {
+ }
+
+ virtual bool Item(cChunk * a_Chunk)
+ {
+ return m_Callback(*a_Chunk);
+ }
+
+ private:
+ std::function<bool(cChunk &)> m_Callback;
+ } callback(a_Callback);
+ return DoWithChunk(ChunkX, ChunkZ, callback);
+}
+
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 0fac79c84..e9f1b94c0 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -104,6 +104,9 @@ public:
/** Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */
bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback);
+ /** Calls the callback for the chunk at the block position specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback **/
+ bool DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback);
+
/** Wakes up simulators for the specified block */
void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ);
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 60a2f8873..b12ab419b 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -2374,6 +2374,15 @@ void cClientHandle::SendParticleEffect(const AString & a_ParticleName, float a_S
+void cClientHandle::SendParticleEffect(const AString & a_ParticleName, const Vector3f a_Src, const Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data)
+{
+ m_Protocol->SendParticleEffect(a_ParticleName, a_Src, a_Offset, a_ParticleData, a_ParticleAmount, a_Data);
+}
+
+
+
+
+
void cClientHandle::SendPickupSpawn(const cPickup & a_Pickup)
{
m_Protocol->SendPickupSpawn(a_Pickup);
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 9e5287985..7992d6bc2 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -22,6 +22,7 @@
#include "ChunkSender.h"
+#include <array>
@@ -177,6 +178,7 @@ public: // tolua_export
void SendMapInfo (int a_ID, unsigned int a_Scale);
void SendPaintingSpawn (const cPainting & a_Painting);
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_ParticleAmount);
+ void SendParticleEffect (const AString & a_ParticleName, const Vector3f a_Src, const Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data);
void SendPickupSpawn (const cPickup & a_Pickup);
void SendPlayerAbilities (void);
void SendPlayerListAddPlayer (const cPlayer & a_Player);
diff --git a/src/Entities/Floater.cpp b/src/Entities/Floater.cpp
index cf8dd6c6f..0c868270d 100644
--- a/src/Entities/Floater.cpp
+++ b/src/Entities/Floater.cpp
@@ -6,7 +6,7 @@
#include "Floater.h"
#include "Player.h"
#include "../ClientHandle.h"
-
+#include "Broadcaster.h"
@@ -145,12 +145,12 @@ void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
LOGD("Started producing particles for floater %i", GetUniqueID());
m_ParticlePos.Set(GetPosX() + (-4 + m_World->GetTickRandomNumber(8)), GetPosY(), GetPosZ() + (-4 + m_World->GetTickRandomNumber(8)));
- m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
+ m_World->GetBroadcaster().BroadcastParticleEffect("splash", static_cast<Vector3f>(m_ParticlePos), Vector3f{}, 0, 15);
}
else if (m_CountDownTime < 20)
{
m_ParticlePos = (m_ParticlePos + (GetPosition() - m_ParticlePos) / 6);
- m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
+ m_World->GetBroadcaster().BroadcastParticleEffect("splash", static_cast<Vector3f>(m_ParticlePos), Vector3f{}, 0, 15);
}
m_CountDownTime--;
diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp
index ebfb5b630..6fc9e06c3 100644
--- a/src/Mobs/Path.cpp
+++ b/src/Mobs/Path.cpp
@@ -220,7 +220,7 @@ void cPath::FinishCalculation()
}
m_Map.clear();
- m_OpenList.empty();
+ m_OpenList = std::priority_queue<cPathCell *, std::vector<cPathCell *>, compareHeuristics>{};
}
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index c66763f17..3c2ec1520 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -5,6 +5,7 @@
#include "../World.h"
#include "../Entities/Player.h"
#include "../Items/ItemHandler.h"
+#include "Broadcaster.h"
@@ -83,13 +84,13 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
SetIsTame(true);
SetOwner(a_Player.GetName(), a_Player.GetUUID());
m_World->BroadcastEntityStatus(*this, esWolfTamed);
- m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
+ m_World->GetBroadcaster().BroadcastParticleEffect("heart", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
}
else
{
// Taming failed
m_World->BroadcastEntityStatus(*this, esWolfTaming);
- m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
+ m_World->GetBroadcaster().BroadcastParticleEffect("smoke", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
}
}
}
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index d8399049e..3bca7551b 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -16,6 +16,8 @@
#include "../Map.h"
#include "../ByteBuffer.h"
+#include <array>
+
@@ -98,6 +100,7 @@ public:
virtual void SendPlayerAbilities (void) = 0;
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0;
virtual void SendParticleEffect (const AString & a_SoundName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) = 0;
+ virtual void SendParticleEffect (const AString & a_SoundName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data) = 0;
virtual void SendPlayerListAddPlayer (const cPlayer & a_Player) = 0;
virtual void SendPlayerListRemovePlayer (const cPlayer & a_Player) = 0;
virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) = 0;
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 8e7d526ef..57631c37d 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -804,6 +804,16 @@ void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_Sr
+void cProtocol172::SendParticleEffect(const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data)
+{
+ // 1.72 doesn't support extra data
+ this->SendParticleEffect(a_ParticleName, a_Src.x, a_Src.y, a_Src.z, a_Offset.x, a_Offset.y, a_Offset.z, a_ParticleData, a_ParticleAmount);
+}
+
+
+
+
+
void cProtocol172::SendPlayerListAddPlayer(const cPlayer & a_Player)
{
ASSERT(m_State == 3); // In game mode?
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 1212cc325..773c39f87 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -99,6 +99,7 @@ public:
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
virtual void SendPaintingSpawn (const cPainting & a_Painting) 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_ParticleAmount) override;
+ virtual void SendParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data) override;
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override;
virtual void SendPlayerListAddPlayer (const cPlayer & a_Player) override;
diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp
index 4429ca683..628d8f528 100644
--- a/src/Protocol/Protocol18x.cpp
+++ b/src/Protocol/Protocol18x.cpp
@@ -802,6 +802,50 @@ void cProtocol180::SendParticleEffect(const AString & a_ParticleName, float a_Sr
+void cProtocol180::SendParticleEffect(const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data)
+{
+ ASSERT(m_State == 3); // In game mode?
+ int ParticleID = GetParticleID(a_ParticleName);
+
+ cPacketizer Pkt(*this, 0x2A);
+ Pkt.WriteBEInt32(ParticleID);
+ Pkt.WriteBool(false);
+ Pkt.WriteBEFloat(a_Src.x);
+ Pkt.WriteBEFloat(a_Src.y);
+ Pkt.WriteBEFloat(a_Src.z);
+ Pkt.WriteBEFloat(a_Offset.x);
+ Pkt.WriteBEFloat(a_Offset.y);
+ Pkt.WriteBEFloat(a_Offset.z);
+ Pkt.WriteBEFloat(a_ParticleData);
+ Pkt.WriteBEInt32(a_ParticleAmount);
+ switch (ParticleID)
+ {
+ // iconcrack
+ case 36:
+ {
+ Pkt.WriteVarInt32(static_cast<UInt32>(a_Data[0]));
+ Pkt.WriteVarInt32(static_cast<UInt32>(a_Data[1]));
+ break;
+ }
+ // blockcrack
+ // blockdust
+ case 37:
+ case 38:
+ {
+ Pkt.WriteVarInt32(static_cast<UInt32>(a_Data[0]));
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+
+
+
+
void cProtocol180::SendPlayerListAddPlayer(const cPlayer & a_Player)
{
ASSERT(m_State == 3); // In game mode?
diff --git a/src/Protocol/Protocol18x.h b/src/Protocol/Protocol18x.h
index 9aa5ed827..21024d702 100644
--- a/src/Protocol/Protocol18x.h
+++ b/src/Protocol/Protocol18x.h
@@ -97,6 +97,7 @@ public:
virtual void SendPlayerAbilities (void) override;
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) 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_ParticleAmount) override;
+ virtual void SendParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data) override;
virtual void SendPlayerListAddPlayer (const cPlayer & a_Player) override;
virtual void SendPlayerListRemovePlayer (const cPlayer & a_Player) override;
virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) override;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 36f8bc791..e7f7a4526 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -439,6 +439,17 @@ void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, flo
+
+void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendParticleEffect(a_ParticleName, a_Src, a_Offset, a_ParticleData, a_ParticleAmount, a_Data);
+}
+
+
+
+
+
void cProtocolRecognizer::SendPaintingSpawn(const cPainting & a_Painting)
{
m_Protocol->SendPaintingSpawn(a_Painting);
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index 13be9478f..6c2185d6d 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -81,6 +81,7 @@ public:
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale) override;
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) 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_ParticleAmount) override;
+ virtual void SendParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array<int, 2> a_Data) override;
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override;
diff --git a/src/World.cpp b/src/World.cpp
index 87209e4c2..6c2e31965 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -57,7 +57,7 @@
#include <stdlib.h>
#endif
-
+#include "Broadcaster.h"
@@ -1459,6 +1459,15 @@ bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback
+bool cWorld::DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback)
+{
+ return m_ChunkMap->DoWithChunkAt(a_BlockPos, a_Callback);
+}
+
+
+
+
+
void cWorld::GrowTree(int a_X, int a_Y, int a_Z)
{
if (GetBlock(a_X, a_Y, a_Z) == E_BLOCK_SAPLING)
@@ -2241,14 +2250,6 @@ void cWorld::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation
-void cWorld::BroadcastParticleEffect(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_ParticleAmount, cClientHandle * a_Exclude)
-{
- m_ChunkMap->BroadcastParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmount, a_Exclude);
-}
-
-
-
-
void cWorld::BroadcastPlayerListAddPlayer(const cPlayer & a_Player, const cClientHandle * a_Exclude)
{
@@ -3770,5 +3771,10 @@ void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_Ch
+cBroadcaster cWorld::GetBroadcaster()
+{
+ return cBroadcaster(this);
+}
+
diff --git a/src/World.h b/src/World.h
index 1de241f60..624262cd3 100644
--- a/src/World.h
+++ b/src/World.h
@@ -55,6 +55,7 @@ class cMobHeadEntity;
class cCompositeChat;
class cCuboid;
class cSetChunkData;
+class cBroadcaster;
typedef std::list< cPlayer * > cPlayerList;
@@ -243,7 +244,6 @@ public:
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = nullptr);
void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr);
virtual void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = nullptr) override; // tolua_export
- void BroadcastParticleEffect (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_ParticleAmount, cClientHandle * a_Exclude = nullptr); // tolua_export
void BroadcastPlayerListAddPlayer (const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr);
void BroadcastPlayerListRemovePlayer (const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr);
void BroadcastPlayerListUpdateGameMode (const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr);
@@ -610,6 +610,9 @@ public:
/** Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */
bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback);
+ /** Calls the callback for the chunk at the block position specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback **/
+ bool DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback);
+
void GrowTreeImage(const sSetBlockVector & a_Blocks);
// tolua_begin
@@ -828,6 +831,8 @@ public:
This function allows nesting and task-concurrency (multiple separate tasks can request ticking and as long
as at least one requests is active the chunk will be ticked). */
void SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked = true); // tolua_export
+
+ cBroadcaster GetBroadcaster();
private: