summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Server/Plugins/APIDump/APIDesc.lua17
-rw-r--r--src/Bindings/AllToLua.pkg5
-rw-r--r--src/Bindings/CMakeLists.txt2
-rw-r--r--src/Bindings/LuaState.cpp36
-rw-r--r--src/Bindings/LuaState.h3
-rw-r--r--src/Bindings/ManualBindings.cpp597
-rw-r--r--src/Bindings/Plugin.h9
-rw-r--r--src/Bindings/PluginLua.cpp10
-rw-r--r--src/Bindings/PluginLua.h6
-rw-r--r--src/Bindings/PluginManager.cpp10
-rw-r--r--src/Bindings/PluginManager.h3
-rw-r--r--src/ByteBuffer.cpp35
-rw-r--r--src/ByteBuffer.h101
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/ChannelCallback.cpp34
-rw-r--r--src/ChannelCallback.h14
-rw-r--r--src/ChannelManager.cpp222
-rw-r--r--src/ChannelManager.h66
-rw-r--r--src/ClientHandle.cpp61
-rw-r--r--src/ClientHandle.h25
-rw-r--r--src/Protocol/Protocol18x.cpp27
-rw-r--r--src/Protocol/Protocol19x.cpp29
-rw-r--r--src/Root.h5
-rw-r--r--src/Server.cpp17
-rw-r--r--src/Server.h12
25 files changed, 1184 insertions, 166 deletions
diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua
index 40bda49d7..5351b98e9 100644
--- a/Server/Plugins/APIDump/APIDesc.lua
+++ b/Server/Plugins/APIDump/APIDesc.lua
@@ -437,6 +437,22 @@ return
},
}, -- cBlockInfo
+ cChannelManager =
+ {
+ Desc = [[
+ This class allows plugins to register handlers for specific plugin channels.
+ ]],
+
+ Functions =
+ {
+ AddClientToChannel = { Params = "{{cClientHandle}}, Channel Name", Notes = "Adds and registers a client on the specified channel." },
+ RemoveClientFromChannel = { Params = "{{cClientHandle}}, Channel Name", Notes = "Removes and unregisters a client on the specified channel." },
+ RegisterChannel = { Params = "Channel Name, Callback", Return = "bool", Notes = "Registers a handler for a specific channel. Returns true if it was able to be registered." },
+ RemoveChannel = { Params = "Channel Name", Return = "bool", Notes = "Removes the handler for the specified channel. Returns true if the handler was removed." },
+ BroadcastChannelMessage = { Params = "Channel Name, Message, {{cWorld|World}}", Notes = "Sends the message on the specified channel. Limits the message to the specified world, if provided." }
+ }
+ }, -- cChannelManager
+
cChatColor =
{
Desc = [[
@@ -2288,6 +2304,7 @@ end
Functions =
{
DoesAllowMultiLogin = { Params = "", Return = "boolean", Notes = "Returns true if players can log in multiple times from the same account (normally used for debugging), false if only one player per name is allowed." },
+ GetChannelManager = { Return = "{{cChannelManager}}", Notes = "Returns the {{cChannelManager|Channel Manager}}." },
GetDescription = { Return = "string", Notes = "Returns the server description set in the settings.ini." },
GetMaxPlayers = { Return = "number", Notes = "Returns the max amount of players who can join the server." },
GetNumPlayers = { Return = "number", Notes = "Returns the amount of players online." },
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 6ca9c8658..1e8c797be 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -42,10 +42,12 @@ $cfile "LuaWindow.h"
$cfile "../BlockID.h"
$cfile "../BlockInfo.h"
+$cfile "../ByteBuffer.h"
$cfile "../StringUtils.h"
$cfile "../Defines.h"
$cfile "../ChatColor.h"
$cfile "../ClientHandle.h"
+$cfile "../ChannelManager.h"
$cfile "../Server.h"
$cfile "../World.h"
$cfile "../Inventory.h"
@@ -125,6 +127,3 @@ typedef unsigned char Byte;
$renaming Vector3<double> @ Vector3d
$renaming Vector3<float> @ Vector3f
$renaming Vector3<int> @ Vector3i
-
-
-
diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt
index 640fd60fa..e9adde150 100644
--- a/src/Bindings/CMakeLists.txt
+++ b/src/Bindings/CMakeLists.txt
@@ -84,6 +84,8 @@ set(BINDING_DEPENDENCIES
../BlockID.h
../BlockInfo.h
../BoundingBox.h
+ ../ByteBuffer.h
+ ../ChannelManager.h
../ChatColor.h
../ChunkDef.h
../ClientHandle.h
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 5e6c24365..75e667821 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -798,6 +798,18 @@ void cLuaState::Push(const Vector3i * a_Vector)
+void cLuaState::Push(const cByteBuffer & a_Buffer)
+{
+ ASSERT(IsValid());
+
+ tolua_pushusertype(m_LuaState, reinterpret_cast<void *>(const_cast<cByteBuffer *>(&a_Buffer)), "cByteBuffer");
+ m_NumCurrentFunctionArgs += 1;
+}
+
+
+
+
+
void cLuaState::Push(bool a_Value)
{
ASSERT(IsValid());
@@ -948,6 +960,18 @@ void cLuaState::Push(long a_Value)
+void cLuaState::Push(const Int64 a_Value)
+{
+ ASSERT(IsValid());
+
+ tolua_pushnumber(m_LuaState, a_Value);
+ m_NumCurrentFunctionArgs += 1;
+}
+
+
+
+
+
void cLuaState::Push(UInt32 a_Value)
{
ASSERT(IsValid());
@@ -960,6 +984,18 @@ void cLuaState::Push(UInt32 a_Value)
+void cLuaState::Push(const UInt64 a_Value)
+{
+ ASSERT(IsValid());
+
+ tolua_pushnumber(m_LuaState, a_Value);
+ m_NumCurrentFunctionArgs += 1;
+}
+
+
+
+
+
void cLuaState::Push(std::chrono::milliseconds a_Value)
{
ASSERT(IsValid());
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index 106d8a783..f89076d95 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -358,6 +358,7 @@ public:
void Push(const Vector3d * a_Vector);
void Push(const Vector3i & a_Vector);
void Push(const Vector3i * a_Vector);
+ void Push(const cByteBuffer & a_Buffer);
// Push a simple value onto the stack (keep alpha-sorted):
void Push(bool a_Value);
@@ -368,7 +369,9 @@ public:
void Push(double a_Value);
void Push(int a_Value);
void Push(long a_Value);
+ void Push(const Int64 a_Value);
void Push(const UInt32 a_Value);
+ void Push(const UInt64 a_Value);
void Push(std::chrono::milliseconds a_time);
/** Pops the specified number of values off the top of the Lua stack. */
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 8bcd5a4e6..d288d37f7 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -18,6 +18,7 @@
#include "../Entities/Player.h"
#include "../WebAdmin.h"
#include "../ClientHandle.h"
+#include "../ChannelManager.h"
#include "../BlockArea.h"
#include "../BlockEntities/BeaconEntity.h"
#include "../BlockEntities/BrewingstandEntity.h"
@@ -39,6 +40,7 @@
#include "../BuildInfo.h"
#include "../HTTP/UrlParser.h"
#include "../BoundingBox.h"
+#include "../ChannelCallback.h"
@@ -3718,6 +3720,571 @@ static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S)
+static int tolua_cChannelManager_RegisterChannel(lua_State * tolua_S)
+{
+
+ // Retrieve the cPlugin from the LuaState:
+ cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S);
+ if (Plugin == nullptr)
+ {
+ // An error message has been already printed in GetLuaPlugin()
+ return 0;
+ }
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cChannelManager"))
+ {
+ return 0;
+ }
+ cChannelManager * self = reinterpret_cast<cChannelManager *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (self == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cChannelManager:RegisterChannel'");
+ }
+ if (!L.CheckParamString(2) || !L.CheckParamFunction(3))
+ {
+ return 0;
+ }
+
+ AString Channel;
+ L.GetStackValue(2, Channel);
+ cLuaState::cCallbackPtr Callback;
+ L.GetStackValue(3, Callback);
+ auto ChannelCallback = std::make_shared<cChannelCallback>(*Plugin, Callback);
+
+ auto Result = self->RegisterChannel(Channel, ChannelCallback);
+
+ // Cut away everything from the stack and push on the result of RegisterChannel
+ lua_settop(L, 2);
+ L.Push(Result);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEInt8(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEInt8'");
+ }
+
+ Int8 Value = 0;
+ auto Success = Buffer->ReadBEInt8(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEInt16(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEInt16'");
+ }
+
+ Int16 Value = 0;
+ auto Success = Buffer->ReadBEInt16(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEInt32(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEInt32'");
+ }
+
+ Int32 Value = 0;
+ auto Success = Buffer->ReadBEInt32(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEInt64(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEInt64'");
+ }
+
+ Int64 Value = 0;
+ auto Success = Buffer->ReadBEInt64(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEUInt8(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEUInt8'");
+ }
+
+ UInt8 Value = 0;
+ auto Success = Buffer->ReadBEUInt8(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEUInt16(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEUInt16'");
+ }
+
+ UInt16 Value = 0;
+ auto Success = Buffer->ReadBEUInt16(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEUInt32(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEUInt32'");
+ }
+
+ UInt32 Value = 0;
+ auto Success = Buffer->ReadBEUInt32(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEUInt64(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEUInt64'");
+ }
+
+ UInt64 Value = 0;
+ auto Success = Buffer->ReadBEUInt64(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEFloat(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEFloat'");
+ }
+
+ float Value = 0.0f;
+ auto Success = Buffer->ReadBEFloat(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBEDouble(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEDouble'");
+ }
+
+ double Value = 0.0;
+ auto Success = Buffer->ReadBEDouble(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadBool(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBool'");
+ }
+
+ bool Value = false;
+ auto Success = Buffer->ReadBool(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadVarInt32(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadVarInt32'");
+ }
+
+ UInt32 Value = 0;
+ auto Success = Buffer->ReadVarInt32(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadVarInt64(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadVarInt64'");
+ }
+
+ UInt64 Value = 0;
+ auto Success = Buffer->ReadVarInt64(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadVarUTF8String(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadVarUTF8String'");
+ }
+
+ AString Value;
+ auto Success = Buffer->ReadVarUTF8String(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadLEInt(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadLEInt'");
+ }
+
+ int Value = 0;
+ auto Success = Buffer->ReadLEInt(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadPosition64(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadPosition64'");
+ }
+
+ int X = 0;
+ int Y = 0;
+ int Z = 0;
+ auto Success = Buffer->ReadPosition64(X, Y, Z);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(X);
+ L.Push(Y);
+ L.Push(Z);
+ return 4;
+}
+
+
+
+
+static int tolua_cByteBuffer_ReadString(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadString'");
+ }
+ if (!L.CheckParamNumber(2))
+ {
+ return 0;
+ }
+
+ AString Value;
+ size_t Count;
+ L.GetStackValue(2, Count);
+ auto Success = Buffer->ReadString(Value, Count);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Success);
+ L.Push(Value);
+ return 2;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadAll(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadAll'");
+ }
+
+ AString Value;
+ Buffer->ReadAll(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Value);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cByteBuffer_ReadAgain(lua_State * tolua_S)
+{
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cByteBuffer"))
+ {
+ return 0;
+ }
+
+ cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (Buffer == nullptr)
+ {
+ return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadAgain'");
+ }
+
+ AString Value;
+ Buffer->ReadAll(Value);
+
+ lua_settop(tolua_S, 2);
+ L.Push(Value);
+ return 1;
+}
+
+
+
+
+
void cManualBindings::Bind(lua_State * tolua_S)
{
tolua_beginmodule(tolua_S, nullptr);
@@ -3929,13 +4496,35 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_variable(tolua_S, "PostParams", tolua_get_HTTPRequest_PostParams, nullptr);
tolua_endmodule(tolua_S);
+ tolua_beginmodule(tolua_S, "cChannelManager");
+ tolua_function(tolua_S, "RegisterChannel", tolua_cChannelManager_RegisterChannel);
+ tolua_endmodule(tolua_S);
+
+ tolua_beginmodule(tolua_S, "cByteBuffer");
+ tolua_function(tolua_S, "ReadBEInt8", tolua_cByteBuffer_ReadBEInt8);
+ tolua_function(tolua_S, "ReadBEInt16", tolua_cByteBuffer_ReadBEInt16);
+ tolua_function(tolua_S, "ReadBEInt32", tolua_cByteBuffer_ReadBEInt32);
+ tolua_function(tolua_S, "ReadBEInt64", tolua_cByteBuffer_ReadBEInt64);
+ tolua_function(tolua_S, "ReadBEUInt8", tolua_cByteBuffer_ReadBEUInt8);
+ tolua_function(tolua_S, "ReadBEUInt16", tolua_cByteBuffer_ReadBEUInt16);
+ tolua_function(tolua_S, "ReadBEUInt32", tolua_cByteBuffer_ReadBEUInt32);
+ tolua_function(tolua_S, "ReadBEUInt64", tolua_cByteBuffer_ReadBEUInt64);
+ tolua_function(tolua_S, "ReadBEFloat", tolua_cByteBuffer_ReadBEFloat);
+ tolua_function(tolua_S, "ReadBEDouble", tolua_cByteBuffer_ReadBEDouble);
+ tolua_function(tolua_S, "ReadBool", tolua_cByteBuffer_ReadBool);
+ tolua_function(tolua_S, "ReadVarInt32", tolua_cByteBuffer_ReadVarInt32);
+ tolua_function(tolua_S, "ReadVarInt64", tolua_cByteBuffer_ReadVarInt64);
+ tolua_function(tolua_S, "ReadVarUTF8String", tolua_cByteBuffer_ReadVarUTF8String);
+ tolua_function(tolua_S, "ReadLEInt", tolua_cByteBuffer_ReadLEInt);
+ tolua_function(tolua_S, "ReadPosition64", tolua_cByteBuffer_ReadPosition64);
+ tolua_function(tolua_S, "ReadString", tolua_cByteBuffer_ReadString);
+ tolua_function(tolua_S, "ReadAll", tolua_cByteBuffer_ReadAll);
+ tolua_function(tolua_S, "ReadAgain", tolua_cByteBuffer_ReadAgain);
+ tolua_endmodule(tolua_S);
+
BindNetwork(tolua_S);
BindRankManager(tolua_S);
BindWorld(tolua_S);
tolua_endmodule(tolua_S);
}
-
-
-
-
diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h
index 3276fde67..c477a97aa 100644
--- a/src/Bindings/Plugin.h
+++ b/src/Bindings/Plugin.h
@@ -15,6 +15,13 @@
+
+class cByteBuffer;
+
+
+
+
+
// tolua_begin
class cPlugin
{
@@ -91,7 +98,7 @@ public:
virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0;
virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0;
- virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) = 0;
+ virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const cByteBuffer & a_Message) = 0;
virtual bool OnPluginsLoaded (void) = 0;
virtual bool OnPostCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) = 0;
virtual bool OnPreCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) = 0;
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index d1fc2ae4f..26c221200 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -12,11 +12,14 @@
#endif
#include "PluginLua.h"
+#include "../ByteBuffer.h"
#include "../CommandOutput.h"
#include "PluginManager.h"
#include "../Item.h"
#include "../Root.h"
#include "../WebAdmin.h"
+#include "../ChannelManager.h"
+#include "../Server.h"
extern "C"
{
@@ -185,6 +188,7 @@ void cPluginLua::Unload(void)
{
ClearWebTabs();
super::Unload();
+ cRoot::Get()->GetServer()->GetChannelManager()->HandlePluginUnloading(this);
Close();
}
@@ -762,7 +766,7 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block
-bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message)
+bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const cByteBuffer & a_Message)
{
return CallSimpleHooks(cPluginManager::HOOK_PLUGIN_MESSAGE, &a_Client, a_Channel, a_Message);
}
@@ -1148,7 +1152,3 @@ void cPluginLua::ClearWebTabs(void)
webAdmin->RemoveAllPluginWebTabs(m_Name);
}
}
-
-
-
-
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index dc3c91880..de9343b08 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -119,7 +119,7 @@ public:
virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
- virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) override;
+ virtual bool OnPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const cByteBuffer & a_Message) override;
virtual bool OnPluginsLoaded (void) override;
virtual bool OnPostCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override;
virtual bool OnPreCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override;
@@ -207,7 +207,3 @@ protected:
return false;
}
} ; // tolua_export
-
-
-
-
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index 19d2e8b4d..fc37c2e2d 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -1188,14 +1188,20 @@ bool cPluginManager::CallHookPlayerUsingItem(cPlayer & a_Player, int a_BlockX, i
-bool cPluginManager::CallHookPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message)
+bool cPluginManager::CallHookPluginMessage(cClientHandle & a_Client, const AString & a_Channel, cByteBuffer & a_Buffer)
{
FIND_HOOK(HOOK_PLUGIN_MESSAGE);
VERIFY_HOOK;
+ a_Buffer.CommitRead();
+ AString Data;
+ a_Buffer.ReadAll(Data);
+ cByteBuffer Temp(Data.size());
+
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
{
- if ((*itr)->OnPluginMessage(a_Client, a_Channel, a_Message))
+ Temp.WriteBuf(Data.c_str(), Data.size());
+ if ((*itr)->OnPluginMessage(a_Client, a_Channel, Temp))
{
return true;
}
diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h
index 0423d6af1..9ce88e583 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -11,6 +11,7 @@
// fwd:
class cBlockEntityWithItems;
class cBrewingstandEntity;
+class cByteBuffer;
class cChunkDesc;
class cClientHandle;
class cCommandOutputCallback;
@@ -267,7 +268,7 @@ public:
bool CallHookPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
bool CallHookPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
bool CallHookPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
- bool CallHookPluginMessage (cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message);
+ bool CallHookPluginMessage (cClientHandle & a_Client, const AString & a_Channel, cByteBuffer & a_Buffer);
bool CallHookPluginsLoaded (void);
bool CallHookPostCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe);
bool CallHookPreCrafting (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe);
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index 77e3f61fd..4a1e6f13a 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -117,6 +117,20 @@ cByteBuffer::cByteBuffer(size_t a_BufferSize) :
+cByteBuffer::cByteBuffer(const cByteBuffer & a_ByteBuffer)
+{
+ m_Buffer = new char[a_ByteBuffer.m_BufferSize];
+ m_BufferSize = a_ByteBuffer.m_BufferSize;
+ m_DataStart = a_ByteBuffer.m_DataStart;
+ m_WritePos = a_ByteBuffer.m_WritePos;
+ m_ReadPos = a_ByteBuffer.m_ReadPos;
+ memcpy(m_Buffer, a_ByteBuffer.m_Buffer, m_BufferSize);
+}
+
+
+
+
+
cByteBuffer::~cByteBuffer()
{
CheckValid();
@@ -986,3 +1000,24 @@ size_t cByteBuffer::GetVarIntSize(UInt32 a_Value)
+cByteBuffer * cByteBuffer::Create(size_t a_BufferSize)
+{
+ return new cByteBuffer(a_BufferSize);
+}
+
+
+
+
+
+void cByteBuffer::Destroy(cByteBuffer * a_ByteBuffer)
+{
+ if (a_ByteBuffer != nullptr)
+ {
+ delete a_ByteBuffer;
+ }
+}
+
+
+
+
+
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index 128a907b2..9800de83d 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -24,50 +24,54 @@ To re-start reading from the beginning, call ResetRead().
This class doesn't implement thread safety, the clients of this class need to provide
their own synchronization.
*/
+// tolua_begin
class cByteBuffer
{
+// tolua_end
public:
cByteBuffer(size_t a_BufferSize);
+ cByteBuffer(const cByteBuffer & a_ByteBuffer);
~cByteBuffer();
/** Writes the bytes specified to the ringbuffer. Returns true if successful, false if not */
bool Write(const void * a_Bytes, size_t a_Count);
/** Returns the number of bytes that can be successfully written to the ringbuffer */
- size_t GetFreeSpace(void) const;
+ size_t GetFreeSpace(void) const; // tolua_export
/** Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes() */
- size_t GetUsedSpace(void) const;
+ size_t GetUsedSpace(void) const; // tolua_export
/** Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already) */
- size_t GetReadableSpace(void) const;
+ size_t GetReadableSpace(void) const; // tolua_export
/** Returns the current data start index. For debugging purposes. */
size_t GetDataStart(void) const { return m_DataStart; }
/** Returns true if the specified amount of bytes are available for reading */
- bool CanReadBytes(size_t a_Count) const;
+ bool CanReadBytes(size_t a_Count) const; // tolua_export
/** Returns true if the specified amount of bytes are available for writing */
- bool CanWriteBytes(size_t a_Count) const;
+ bool CanWriteBytes(size_t a_Count) const; // tolua_export
// Read the specified datatype and advance the read pointer; return true if successfully read:
- bool ReadBEInt8 (Int8 & a_Value);
- bool ReadBEInt16 (Int16 & a_Value);
- bool ReadBEInt32 (Int32 & a_Value);
- bool ReadBEInt64 (Int64 & a_Value);
- bool ReadBEUInt8 (UInt8 & a_Value);
- bool ReadBEUInt16 (UInt16 & a_Value);
- bool ReadBEUInt32 (UInt32 & a_Value);
- bool ReadBEUInt64 (UInt64 & a_Value);
- bool ReadBEFloat (float & a_Value);
- bool ReadBEDouble (double & a_Value);
- bool ReadBool (bool & a_Value);
- bool ReadVarInt32 (UInt32 & a_Value);
- bool ReadVarInt64 (UInt64 & a_Value);
- bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
- bool ReadLEInt (int & a_Value);
- bool ReadPosition64 (int & a_BlockX, int & a_BlockY, int & a_BlockZ);
+ bool ReadBEInt8 (Int8 & a_Value); // exported in manual bindings
+ bool ReadBEInt16 (Int16 & a_Value); // exported in manual bindings
+ bool ReadBEInt32 (Int32 & a_Value); // exported in manual bindings
+ bool ReadBEInt64 (Int64 & a_Value); // exported in manual bindings
+ bool ReadBEUInt8 (UInt8 & a_Value); // exported in manual bindings
+ bool ReadBEUInt16 (UInt16 & a_Value); // exported in manual bindings
+ bool ReadBEUInt32 (UInt32 & a_Value); // exported in manual bindings
+ bool ReadBEUInt64 (UInt64 & a_Value); // exported in manual bindings
+ bool ReadBEFloat (float & a_Value); // exported in manual bindings
+ bool ReadBEDouble (double & a_Value); // exported in manual bindings
+ bool ReadBool (bool & a_Value); // exported in manual bindings
+ bool ReadVarInt32 (UInt32 & a_Value); // exported in manual bindings
+ bool ReadVarInt64 (UInt64 & a_Value); // exported in manual bindings
+ // string length as VarInt, then string as UTF-8.
+ bool ReadVarUTF8String (AString & a_Value); // exported in manual bindings
+ bool ReadLEInt (int & a_Value); // exported in manual bindings
+ bool ReadPosition64 (int & a_BlockX, int & a_BlockY, int & a_BlockZ); // exported in manual bindings
/** Reads VarInt, assigns it to anything that can be assigned from an UInt64 (unsigned short, char, Byte, double, ...) */
template <typename T> bool ReadVarInt(T & a_Value)
@@ -82,22 +86,23 @@ public:
}
// Write the specified datatype; return true if successfully written
- bool WriteBEInt8 (Int8 a_Value);
- bool WriteBEInt16 (Int16 a_Value);
- bool WriteBEInt32 (Int32 a_Value);
- bool WriteBEInt64 (Int64 a_Value);
- bool WriteBEUInt8 (UInt8 a_Value);
- bool WriteBEUInt16 (UInt16 a_Value);
- bool WriteBEUInt32 (UInt32 a_Value);
- bool WriteBEUInt64 (UInt64 a_Value);
- bool WriteBEFloat (float a_Value);
- bool WriteBEDouble (double a_Value);
- bool WriteBool (bool a_Value);
- bool WriteVarInt32 (UInt32 a_Value);
- bool WriteVarInt64 (UInt64 a_Value);
- bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8
- bool WriteLEInt32 (Int32 a_Value);
- bool WritePosition64 (Int32 a_BlockX, Int32 a_BlockY, Int32 a_BlockZ);
+ bool WriteBEInt8 (Int8 a_Value); // tolua_export
+ bool WriteBEInt16 (Int16 a_Value); // tolua_export
+ bool WriteBEInt32 (Int32 a_Value); // tolua_export
+ bool WriteBEInt64 (Int64 a_Value); // tolua_export
+ bool WriteBEUInt8 (UInt8 a_Value); // tolua_export
+ bool WriteBEUInt16 (UInt16 a_Value); // tolua_export
+ bool WriteBEUInt32 (UInt32 a_Value); // tolua_export
+ bool WriteBEUInt64 (UInt64 a_Value); // tolua_export
+ bool WriteBEFloat (float a_Value); // tolua_export
+ bool WriteBEDouble (double a_Value); // tolua_export
+ bool WriteBool (bool a_Value); // tolua_export
+ bool WriteVarInt32 (UInt32 a_Value); // tolua_export
+ bool WriteVarInt64 (UInt64 a_Value); // tolua_export
+ // string length as VarInt, then string as UTF-8
+ bool WriteVarUTF8String (const AString & a_Value); // tolua_export
+ bool WriteLEInt32 (Int32 a_Value); // tolua_export
+ bool WritePosition64 (Int32 a_BlockX, Int32 a_BlockY, Int32 a_BlockZ); // tolua_export
/** Reads a_Count bytes into a_Buffer; returns true if successful */
bool ReadBuf(void * a_Buffer, size_t a_Count);
@@ -106,31 +111,35 @@ public:
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, size_t a_Count);
+ bool ReadString(AString & a_String, size_t a_Count); // exported im manual bindings
/** Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer */
- bool SkipRead(size_t a_Count);
+ bool SkipRead(size_t a_Count); // tolua_export
/** Reads all available data into a_Data */
- void ReadAll(AString & a_Data);
+ void ReadAll(AString & a_Data); // exported in manual bindings
/** Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. */
bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes);
/** Removes the bytes that have been read from the ringbuffer */
- void CommitRead(void);
+ void CommitRead(void); // tolua_export
/** Restarts next reading operation at the start of the ringbuffer */
- void ResetRead(void);
+ void ResetRead(void); // tolua_export
/** Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication */
- void ReadAgain(AString & a_Out);
+ void ReadAgain(AString & a_Out); // exported in manual bindings
/** Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs */
- void CheckValid(void) const;
+ void CheckValid(void) const; // tolua_export
/** Gets the number of bytes that are needed to represent the given VarInt */
- static size_t GetVarIntSize(UInt32 a_Value);
+ static size_t GetVarIntSize(UInt32 a_Value); // tolua_export
+
+ static cByteBuffer * Create(size_t a_BufferSize); // tolua_export
+
+ static void Destroy(cByteBuffer * a_ByteBuffer); // tolua_export
protected:
char * m_Buffer;
@@ -148,7 +157,7 @@ protected:
/** Advances the m_ReadPos by a_Count bytes */
void AdvanceReadPos(size_t a_Count);
-} ;
+}; // tolua_export
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 11e2f8376..f3fd7a824 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,8 @@ SET (SRCS
BoundingBox.cpp
ByteBuffer.cpp
ChatColor.cpp
+ ChannelCallback.cpp
+ ChannelManager.cpp
Chunk.cpp
ChunkData.cpp
ChunkMap.cpp
@@ -90,6 +92,8 @@ SET (HDRS
BuildInfo.h.cmake
ByteBuffer.h
ChatColor.h
+ ChannelCallback.h
+ ChannelManager.h
Chunk.h
ChunkData.h
ChunkDataCallback.h
diff --git a/src/ChannelCallback.cpp b/src/ChannelCallback.cpp
new file mode 100644
index 000000000..efa11d69a
--- /dev/null
+++ b/src/ChannelCallback.cpp
@@ -0,0 +1,34 @@
+
+// ChannelCallback.cpp
+
+// Implements the cChannelCallback class representing the callbacks used for plugin channel management
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "ChannelCallback.h"
+#include "ByteBuffer.h"
+#include "ClientHandle.h"
+
+cChannelCallback::cChannelCallback(cPluginLua & a_Plugin, cLuaState::cCallbackPtr & a_Callback)
+{
+ m_Plugin = &a_Plugin;
+ m_Callback = std::move(a_Callback);
+}
+
+void cChannelCallback::Call(cClientHandle & a_Handle, const cByteBuffer & a_Data)
+{
+ cCSLock Lock(m_CSPlugin);
+ if (m_Callback->IsValid())
+ {
+ m_Callback->Call(a_Handle.GetPlayer(), a_Data);
+ }
+}
+
+
+
+
+
+bool cChannelCallback::BelongsTo(const cPluginLua * a_Plugin)
+{
+ return (a_Plugin == m_Plugin);
+}
diff --git a/src/ChannelCallback.h b/src/ChannelCallback.h
new file mode 100644
index 000000000..e9fc145f5
--- /dev/null
+++ b/src/ChannelCallback.h
@@ -0,0 +1,14 @@
+#include "Bindings/PluginLua.h"
+
+class cByteBuffer;
+
+class cChannelCallback
+{
+ cLuaState::cCallbackPtr m_Callback;
+ cPluginLua * m_Plugin;
+ cCriticalSection m_CSPlugin;
+public:
+ cChannelCallback(cPluginLua & a_Plugin, cLuaState::cCallbackPtr & a_Callback);
+ void Call(cClientHandle & a_Handle, const cByteBuffer & a_Data);
+ bool BelongsTo(const cPluginLua * a_Plugin);
+};
diff --git a/src/ChannelManager.cpp b/src/ChannelManager.cpp
new file mode 100644
index 000000000..3d0f326b7
--- /dev/null
+++ b/src/ChannelManager.cpp
@@ -0,0 +1,222 @@
+// ChannelManager.cpp
+
+// Implements the cChannelManager class which stores and calls channel callbacks
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include <algorithm>
+
+#include "ByteBuffer.h"
+#include "ChannelManager.h"
+#include "ChannelCallback.h"
+#include "ClientHandle.h"
+#include "Entities/Player.h"
+#include "OSSupport/CriticalSection.h"
+#include "World.h"
+
+
+
+
+
+class cChannelBroadcastCallback : public cPlayerListCallback
+{
+public:
+ cChannelBroadcastCallback(const AString & a_Channel, const AString & a_Data)
+ : m_Channel(a_Channel), m_Data(a_Data){}
+
+ virtual bool Item(cPlayer * a_Type)
+ {
+ cClientHandle * Handle = a_Type->GetClientHandle();
+ if (Handle->HasPluginChannel(m_Channel))
+ {
+ Handle->SendPluginMessage(m_Channel, m_Data);
+ }
+ return false;
+ }
+private:
+ AString m_Channel;
+ AString m_Data;
+};
+
+
+
+
+
+bool cChannelManager::RegisterChannel(const AString & a_Channel, cChannelCallbackPtr a_Callback)
+{
+ cCSLock Lock(m_CSCallbacks);
+ auto Result = m_ChannelCallbacks.emplace(a_Channel, a_Callback);
+
+ return Result.second;
+}
+
+
+
+
+
+bool cChannelManager::RemoveChannel(const AString & a_Channel)
+{
+ cCSLock Lock(m_CSCallbacks);
+ auto callback = m_ChannelCallbacks.find(a_Channel);
+ if (callback != m_ChannelCallbacks.end())
+ {
+ m_ChannelCallbacks.erase(callback);
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
+void cChannelManager::AddClientToChannel(cClientHandle & a_Client, const AString & a_Channel)
+{
+ a_Client.RegisterChannel(a_Channel);
+ a_Client.SendPluginMessage("REGISTER", a_Channel);
+}
+
+
+
+
+
+void cChannelManager::AddClientToChannels(cClientHandle & a_Client, const AString & a_Channels)
+{
+ auto channels = BreakApartChannels(a_Channels);
+ a_Client.RegisterChannels(channels);
+}
+
+
+
+
+
+void cChannelManager::RemoveClientFromChannel(cClientHandle & a_Client, const AString & a_Channel)
+{
+ a_Client.UnregisterChannel(a_Channel);
+ a_Client.SendPluginMessage("UNREGISTER", a_Channel);
+}
+
+
+
+
+
+void cChannelManager::RemoveClientFromChannels(cClientHandle & a_Client, const AString & a_Channels)
+{
+ auto channels = BreakApartChannels(a_Channels);
+ a_Client.UnregisterChannels(channels);
+}
+
+
+
+
+
+bool cChannelManager::ClientHasChannel(cClientHandle & a_Client, const AString & a_Channel)
+{
+ return a_Client.HasPluginChannel(a_Channel);
+}
+
+
+
+
+
+void cChannelManager::HandleChannelMessage(cClientHandle & a_Client, const AString & a_Channel, cByteBuffer & a_Data)
+{
+ bool HasChannel = ClientHasChannel(a_Client, a_Channel);
+
+ // If the client has not registered to send and recieve this channel, log it and send an unregister message.
+ // Otherwise try to use it.
+ if (HasChannel)
+ {
+ cCSLock Lock(m_CSCallbacks);
+
+ auto Callback = m_ChannelCallbacks.find(a_Channel);
+
+ // If a callback has been registered for this channel, call it.
+ // Otherwise, call the hook
+ if (HasChannel && (Callback != m_ChannelCallbacks.end()))
+ {
+ Callback->second->Call(a_Client, a_Data);
+ }
+ else
+ {
+ cPluginManager::Get()->CallHookPluginMessage(a_Client, a_Channel, a_Data);
+ }
+ }
+ else
+ {
+ // Ignore if client sent something but didn't register the channel first
+ LOGD("Player %s sent a plugin message on channel \"%s\", but didn't REGISTER it first", a_Client.GetUsername().c_str(), a_Channel.c_str());
+ a_Client.SendPluginMessage("UNREGISTER", a_Channel);
+ }
+
+}
+
+
+
+
+
+void cChannelManager::HandlePluginUnloading(const cPluginLua * a_Plugin)
+{
+ cCSLock Lock(m_CSCallbacks);
+
+ for (auto it = m_ChannelCallbacks.begin(); it != m_ChannelCallbacks.end();)
+ {
+ if (!it->second->BelongsTo(a_Plugin))
+ {
+ ++it;
+ }
+ else
+ {
+ it = m_ChannelCallbacks.erase(it);
+ }
+ }
+}
+
+
+
+
+
+void cChannelManager::BroadcastChannelMessage(const AString & a_Channel, cByteBuffer & a_Data, cWorld * a_World)
+{
+ AString Temp;
+ a_Data.ReadAll(Temp);
+ if (a_World != nullptr)
+ {
+ cChannelBroadcastCallback Callback(a_Channel, Temp);
+ a_World->ForEachPlayer(Callback);
+ }
+ else
+ {
+ // TODO: Implement server-wide broadcast
+ }
+}
+
+
+
+
+
+AStringVector cChannelManager::BreakApartChannels(const AString & a_Channels)
+{
+ // Break the string on each NUL character.
+ // Note that StringSplit() doesn't work on this because NUL is a special char - string terminator
+ size_t len = a_Channels.size();
+ size_t first = 0;
+ AStringVector res;
+ for (size_t i = 0; i < len; i++)
+ {
+ if (a_Channels[i] != 0)
+ {
+ continue;
+ }
+ if (i > first)
+ {
+ res.push_back(a_Channels.substr(first, i - first));
+ }
+ first = i + 1;
+ } // for i - a_PluginChannels[]
+ if (first < len)
+ {
+ res.push_back(a_Channels.substr(first, len - first));
+ }
+ return res;
+}
diff --git a/src/ChannelManager.h b/src/ChannelManager.h
new file mode 100644
index 000000000..874588d29
--- /dev/null
+++ b/src/ChannelManager.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <unordered_map>
+#include <set>
+
+#include "StringUtils.h"
+
+
+class cClientHandle;
+class cCriticalSection;
+class cPluginLua;
+class cWorld;
+class cChannelCallback;
+class cByteBuffer;
+
+// tolua_begin
+class cChannelManager
+{
+// tolua_end
+public:
+ typedef SharedPtr<cChannelCallback> cChannelCallbackPtr;
+ typedef std::unordered_map<AString, cChannelCallbackPtr> CallbackMap;
+
+ /** Adds a client to a specific channel. */
+ void AddClientToChannel (cClientHandle & a_Client, const AString & a_Channel); // tolua_export
+
+ /** Adds a client to multiple channels at once. */
+ void AddClientToChannels (cClientHandle & a_Client, const AString & a_Channels);
+
+ /** Removes a client from a specific channel. */
+ void RemoveClientFromChannel (cClientHandle & a_Client, const AString & a_Channel); // tolua_export
+
+ /** Removes a client from multiple channels at once. */
+ void RemoveClientFromChannels(cClientHandle & a_Client, const AString & a_Channels);
+
+ /** Returns true if the client is registered for the specified channel. */
+ bool ClientHasChannel (cClientHandle & a_Client, const AString & a_Channel);
+
+ /** Broadcasts a channel message to all clients.
+ If a_World is provided, broadcast is limited to that world. */
+ void BroadcastChannelMessage (const AString & a_Channel, cByteBuffer & a_Data, cWorld * a_World = nullptr); // tolua_export
+
+ /** Registers a handler for a specific channel.
+ Returns true if registration was successful. */
+ bool RegisterChannel (const AString & a_Channel, cChannelCallbackPtr a_Callback); // Exported in manual bindings
+
+ /** Removes the handler for the specified channel.
+ Returns true if the handler was removed. */
+ bool RemoveChannel (const AString & a_Channel); // tolua_export
+
+
+ void HandleChannelMessage (cClientHandle & a_Client, const AString & a_Channel, cByteBuffer & a_Data);
+
+
+ void HandlePluginUnloading (const cPluginLua * a_Plugin);
+
+private:
+
+ AStringVector BreakApartChannels(const AString & a_Channels);
+
+ /** This protects m_ChannelCallbacks */
+ cCriticalSection m_CSCallbacks;
+
+ CallbackMap m_ChannelCallbacks;
+
+}; // tolua_export
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 997510684..b44f23abe 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -803,68 +803,25 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
-void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message)
+void cClientHandle::RegisterChannel(const AString & a_Channel)
{
- if (a_Channel == "REGISTER")
- {
- if (HasPluginChannel(a_Channel))
- {
- SendPluginMessage("UNREGISTER", a_Channel);
- return; // Can't register again if already taken - kinda defeats the point of plugin messaging!
- }
-
- RegisterPluginChannels(BreakApartPluginChannels(a_Message));
- }
- else if (a_Channel == "UNREGISTER")
- {
- UnregisterPluginChannels(BreakApartPluginChannels(a_Message));
- }
- else if (!HasPluginChannel(a_Channel))
- {
- // Ignore if client sent something but didn't register the channel first
- LOGD("Player %s sent a plugin message on channel \"%s\", but didn't REGISTER it first", GetUsername().c_str(), a_Channel.c_str());
- SendPluginMessage("UNREGISTER", a_Channel);
- return;
- }
-
- cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message);
+ m_PluginChannels.insert(a_Channel);
}
-AStringVector cClientHandle::BreakApartPluginChannels(const AString & a_PluginChannels)
+void cClientHandle::UnregisterChannel(const AString & a_Channel)
{
- // Break the string on each NUL character.
- // Note that StringSplit() doesn't work on this because NUL is a special char - string terminator
- size_t len = a_PluginChannels.size();
- size_t first = 0;
- AStringVector res;
- for (size_t i = 0; i < len; i++)
- {
- if (a_PluginChannels[i] != 0)
- {
- continue;
- }
- if (i > first)
- {
- res.push_back(a_PluginChannels.substr(first, i - first));
- }
- first = i + 1;
- } // for i - a_PluginChannels[]
- if (first < len)
- {
- res.push_back(a_PluginChannels.substr(first, len - first));
- }
- return res;
+ m_PluginChannels.erase(a_Channel);
}
-void cClientHandle::RegisterPluginChannels(const AStringVector & a_ChannelList)
+void cClientHandle::RegisterChannels(const AStringVector & a_ChannelList)
{
for (AStringVector::const_iterator itr = a_ChannelList.begin(), end = a_ChannelList.end(); itr != end; ++itr)
{
@@ -876,7 +833,7 @@ void cClientHandle::RegisterPluginChannels(const AStringVector & a_ChannelList)
-void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList)
+void cClientHandle::UnregisterChannels(const AStringVector & a_ChannelList)
{
for (AStringVector::const_iterator itr = a_ChannelList.begin(), end = a_ChannelList.end(); itr != end; ++itr)
{
@@ -3026,7 +2983,7 @@ void cClientHandle::SetViewDistance(int a_ViewDistance)
bool cClientHandle::HasPluginChannel(const AString & a_PluginChannel)
{
- return (m_PluginChannels.find(a_PluginChannel) != m_PluginChannels.end());
+ return (m_PluginChannels.find(a_PluginChannel) != m_PluginChannels.end()) || (a_PluginChannel == "REGISTER") || (a_PluginChannel == "UNREGISTER");
}
@@ -3185,7 +3142,3 @@ void cClientHandle::OnError(int a_ErrorCode, const AString & a_ErrorMsg)
}
SocketClosed();
}
-
-
-
-
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index c49de647f..73e2105d4 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -331,7 +331,6 @@ public: // tolua_export
void HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, bool a_IsOnGround);
- void HandlePluginMessage (const AString & a_Channel, const AString & a_Message);
void HandleRespawn (void);
void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem);
void HandleSlotSelected (Int16 a_SlotNum);
@@ -368,6 +367,16 @@ public: // tolua_export
bool IsPlayerChunkSent();
+ void RegisterChannel(const AString & a_Channel);
+
+ void UnregisterChannel(const AString & a_Channel);
+
+ /** Adds all of the channels to the list of current plugin channels. Handles duplicates gracefully. */
+ void RegisterChannels(const AStringVector & a_ChannelList);
+
+ /** Removes all of the channels from the list of current plugin channels. Ignores channels that are not found. */
+ void UnregisterChannels(const AStringVector & a_ChannelList);
+
private:
friend class cServer; // Needs access to SetSelf()
@@ -528,15 +537,6 @@ private:
/** The clients will receive a finished dig animation */
void FinishDigAnimation();
- /** Converts the protocol-formatted channel list (NUL-separated) into a proper string vector. */
- AStringVector BreakApartPluginChannels(const AString & a_PluginChannels);
-
- /** Adds all of the channels to the list of current plugin channels. Handles duplicates gracefully. */
- void RegisterPluginChannels(const AStringVector & a_ChannelList);
-
- /** Removes all of the channels from the list of current plugin channels. Ignores channels that are not found. */
- void UnregisterPluginChannels(const AStringVector & a_ChannelList);
-
/** Called when the network socket has been closed. */
void SocketClosed(void);
@@ -549,8 +549,3 @@ private:
virtual void OnRemoteClosed(void) override;
virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override;
}; // tolua_export
-
-
-
-
-
diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp
index ae9571f03..efd9cd5a9 100644
--- a/src/Protocol/Protocol18x.cpp
+++ b/src/Protocol/Protocol18x.cpp
@@ -16,6 +16,7 @@ Implements the 1.8.x protocol classes:
#include "Packetizer.h"
#include "../ClientHandle.h"
+#include "../ChannelManager.h"
#include "../Root.h"
#include "../Server.h"
#include "../World.h"
@@ -2483,10 +2484,24 @@ void cProtocol180::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
return;
}
- // Read the plugin message and relay to clienthandle:
+ // Read the rest of the message
+ cByteBuffer Buffer = a_ByteBuffer;
AString Data;
VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds
- m_Client->HandlePluginMessage(Channel, Data);
+
+ auto manager = cRoot::Get()->GetServer()->GetChannelManager();
+ // Register the client on the requested channels
+ if (Channel == "REGISTER")
+ {
+ manager->AddClientToChannels(*m_Client, Data);
+ }
+ else if (Channel == "UNREGISTER")
+ {
+ manager->RemoveClientFromChannels(*m_Client, Data);
+ }
+
+ // Call the channel message handler
+ manager->HandleChannelMessage(*m_Client, Channel, Buffer);
}
@@ -2738,10 +2753,7 @@ void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
}
LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str());
- // Read the payload and send it through to the clienthandle:
- AString Message;
- VERIFY(a_ByteBuffer.ReadString(Message, a_ByteBuffer.GetReadableSpace() - 1));
- m_Client->HandlePluginMessage(a_Channel, Message);
+ cRoot::Get()->GetServer()->GetChannelManager()->HandleChannelMessage(*m_Client, a_Channel, a_ByteBuffer);
}
@@ -3592,6 +3604,3 @@ void cProtocol180::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_
a_Pkt.WriteBEInt32(0); // NumProperties
}
-
-
-
diff --git a/src/Protocol/Protocol19x.cpp b/src/Protocol/Protocol19x.cpp
index c11e05565..a8c916e5b 100644
--- a/src/Protocol/Protocol19x.cpp
+++ b/src/Protocol/Protocol19x.cpp
@@ -22,6 +22,7 @@ Implements the 1.9.x protocol classes:
#include "Packetizer.h"
#include "../ClientHandle.h"
+#include "../ChannelManager.h"
#include "../Root.h"
#include "../Server.h"
#include "../World.h"
@@ -2552,10 +2553,24 @@ void cProtocol190::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
return;
}
- // Read the plugin message and relay to clienthandle:
+ // Read the rest of the message
+ cByteBuffer Buffer = a_ByteBuffer;
AString Data;
VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds
- m_Client->HandlePluginMessage(Channel, Data);
+
+ auto manager = cRoot::Get()->GetServer()->GetChannelManager();
+ // Register the client on the requested channels
+ if (Channel == "REGISTER")
+ {
+ manager->AddClientToChannels(*m_Client, Data);
+ }
+ else if (Channel == "UNREGISTER")
+ {
+ manager->RemoveClientFromChannels(*m_Client, Data);
+ }
+
+ // Call the channel message handler
+ manager->HandleChannelMessage(*m_Client, Channel, Buffer);
}
@@ -2843,10 +2858,7 @@ void cProtocol190::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const
}
LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str());
- // Read the payload and send it through to the clienthandle:
- AString Message;
- VERIFY(a_ByteBuffer.ReadString(Message, a_ByteBuffer.GetReadableSpace() - 1));
- m_Client->HandlePluginMessage(a_Channel, Message);
+ cRoot::Get()->GetServer()->GetChannelManager()->HandleChannelMessage(*m_Client, a_Channel, a_ByteBuffer);
}
@@ -4381,8 +4393,3 @@ void cProtocol194::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons
Writer.Finish();
Pkt.WriteBuf(Writer.GetResult().data(), Writer.GetResult().size());
}
-
-
-
-
-
diff --git a/src/Root.h b/src/Root.h
index 722554332..864253cc7 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -241,8 +241,3 @@ private:
static void InputThread(cRoot & a_Params);
}; // tolua_export
-
-
-
-
-
diff --git a/src/Server.cpp b/src/Server.cpp
index ba469bd3e..7eb99dfde 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -17,6 +17,7 @@
#include "WebAdmin.h"
#include "Protocol/ProtocolRecognizer.h"
#include "CommandOutput.h"
+#include "ChannelManager.h"
#include "IniFile.h"
#include "Vector3.h"
@@ -89,6 +90,15 @@ public:
+cServer::~cServer()
+{
+ m_ChannelManager = nullptr;
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// cServer::cTickThread:
@@ -147,6 +157,9 @@ cServer::cServer(void) :
{
// Initialize the LuaStateTracker singleton before the app goes multithreaded:
cLuaStateTracker::GetStats();
+
+ // Create a new channel manager
+ m_ChannelManager = UniquePtr<cChannelManager>(new cChannelManager());
}
@@ -705,3 +718,7 @@ void cServer::AuthenticateUser(int a_ClientID, const AString & a_Name, const ASt
+cChannelManager * cServer::GetChannelManager()
+{
+ return m_ChannelManager.get();
+}
diff --git a/src/Server.h b/src/Server.h
index 600e7ca97..6dbbafd11 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -40,6 +40,7 @@ typedef std::list<cClientHandlePtr> cClientHandlePtrs;
typedef std::list<cClientHandle *> cClientHandles;
class cCommandOutputCallback;
class cSettingsRepositoryInterface;
+class cChannelManager;
namespace Json
@@ -57,7 +58,7 @@ class cServer
public:
// tolua_end
- virtual ~cServer() {}
+ virtual ~cServer();
bool InitServer(cSettingsRepositoryInterface & a_Settings, bool a_ShouldAuth);
// tolua_begin
@@ -143,6 +144,9 @@ public:
from the settings. */
bool ShouldAllowMultiWorldTabCompletion(void) const { return m_ShouldAllowMultiWorldTabCompletion; }
+ /** Returns the channel manager. */
+ cChannelManager * GetChannelManager(); // tolua_export
+
private:
friend class cRoot; // so cRoot can create and destroy cServer
@@ -241,6 +245,8 @@ private:
Initialized in InitServer(), used in Start(). */
AStringVector m_Ports;
+ UniquePtr<cChannelManager> m_ChannelManager;
+
cServer(void);
@@ -256,7 +262,3 @@ private:
/** Ticks the clients in m_Clients, manages the list in respect to removing clients */
void TickClients(float a_Dt);
}; // tolua_export
-
-
-
-