summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Bindings/AllToLua.pkg1
-rw-r--r--src/Bindings/CMakeLists.txt3
-rw-r--r--src/Bindings/LuaChunkStay.cpp22
-rw-r--r--src/Bindings/LuaChunkStay.h6
-rw-r--r--src/Bindings/LuaNameLookup.cpp2
-rw-r--r--src/Bindings/LuaServerHandle.cpp2
-rw-r--r--src/Bindings/LuaState.cpp273
-rw-r--r--src/Bindings/LuaState.h164
-rw-r--r--src/Bindings/LuaTCPLink.cpp2
-rw-r--r--src/Bindings/LuaUDPEndpoint.cpp2
-rw-r--r--src/Bindings/LuaWindow.cpp95
-rw-r--r--src/Bindings/LuaWindow.h72
-rw-r--r--src/Bindings/ManualBindings.cpp559
-rw-r--r--src/Bindings/ManualBindings_World.cpp109
-rw-r--r--src/Bindings/Plugin.h15
-rw-r--r--src/Bindings/PluginLua.cpp1392
-rw-r--r--src/Bindings/PluginLua.h132
-rw-r--r--src/Bindings/PluginManager.cpp64
-rw-r--r--src/Bindings/PluginManager.h52
-rw-r--r--src/Bindings/WebPlugin.cpp152
-rw-r--r--src/Bindings/WebPlugin.h80
-rw-r--r--src/Entities/Player.h6
-rw-r--r--src/Server.cpp35
-rw-r--r--src/UI/Window.cpp2
-rw-r--r--src/WebAdmin.cpp415
-rw-r--r--src/WebAdmin.h158
26 files changed, 1559 insertions, 2256 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 991ed0ddd..6ca9c8658 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -38,7 +38,6 @@ $cfile "LuaFunctions.h"
$cfile "PluginManager.h"
$cfile "Plugin.h"
$cfile "PluginLua.h"
-$cfile "WebPlugin.h"
$cfile "LuaWindow.h"
$cfile "../BlockID.h"
diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt
index 10cda1efb..4f25f2cf4 100644
--- a/src/Bindings/CMakeLists.txt
+++ b/src/Bindings/CMakeLists.txt
@@ -23,7 +23,6 @@ SET (SRCS
Plugin.cpp
PluginLua.cpp
PluginManager.cpp
- WebPlugin.cpp
)
SET (HDRS
@@ -44,7 +43,6 @@ SET (HDRS
Plugin.h
PluginLua.h
PluginManager.h
- WebPlugin.h
tolua++.h
)
@@ -66,7 +64,6 @@ set(BINDING_DEPENDENCIES
../Bindings/Plugin.h
../Bindings/PluginLua.h
../Bindings/PluginManager.h
- ../Bindings/WebPlugin.h
../BiomeDef.h
../BlockArea.h
../BlockEntities/BeaconEntity.h
diff --git a/src/Bindings/LuaChunkStay.cpp b/src/Bindings/LuaChunkStay.cpp
index d8d7da5d0..145a9ee1b 100644
--- a/src/Bindings/LuaChunkStay.cpp
+++ b/src/Bindings/LuaChunkStay.cpp
@@ -113,12 +113,10 @@ void cLuaChunkStay::AddChunkCoord(cLuaState & L, int a_Index)
-void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPos, int a_OnAllChunksAvailableStackPos)
+void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, cLuaState::cCallbackPtr a_OnChunkAvailable, cLuaState::cCallbackPtr a_OnAllChunksAvailable)
{
- // Get the references to the callback functions:
- m_LuaState = &m_Plugin.GetLuaState();
- m_OnChunkAvailable.RefStack(*m_LuaState, a_OnChunkAvailableStackPos);
- m_OnAllChunksAvailable.RefStack(*m_LuaState, a_OnAllChunksAvailableStackPos);
+ m_OnChunkAvailable = std::move(a_OnChunkAvailable);
+ m_OnAllChunksAvailable = std::move(a_OnAllChunksAvailable);
// Enable the ChunkStay:
super::Enable(a_ChunkMap);
@@ -130,10 +128,9 @@ void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPo
void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
{
- if (m_OnChunkAvailable.IsValid())
+ if (m_OnChunkAvailable != nullptr)
{
- cPluginLua::cOperation Op(m_Plugin);
- Op().Call(static_cast<int>(m_OnChunkAvailable), a_ChunkX, a_ChunkZ);
+ m_OnChunkAvailable->Call(a_ChunkX, a_ChunkZ);
}
}
@@ -143,15 +140,14 @@ void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
bool cLuaChunkStay::OnAllChunksAvailable(void)
{
- if (m_OnAllChunksAvailable.IsValid())
+ if (m_OnAllChunksAvailable != nullptr)
{
// Call the callback:
- cPluginLua::cOperation Op(m_Plugin);
- Op().Call(static_cast<int>(m_OnAllChunksAvailable));
+ m_OnAllChunksAvailable->Call();
// Remove the callback references - they won't be needed anymore
- m_OnChunkAvailable.UnRef();
- m_OnAllChunksAvailable.UnRef();
+ m_OnChunkAvailable.reset();
+ m_OnAllChunksAvailable.reset();
}
// Disable the ChunkStay by returning true
diff --git a/src/Bindings/LuaChunkStay.h b/src/Bindings/LuaChunkStay.h
index a455d2502..51356d5b7 100644
--- a/src/Bindings/LuaChunkStay.h
+++ b/src/Bindings/LuaChunkStay.h
@@ -39,7 +39,7 @@ public:
bool AddChunks(int a_ChunkCoordTableStackPos);
/** Enables the ChunkStay for the specified chunkmap, with the specified Lua callbacks. */
- void Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPos, int a_OnAllChunksAvailableStackPos);
+ void Enable(cChunkMap & a_ChunkMap, cLuaState::cCallbackPtr a_OnChunkAvailable, cLuaState::cCallbackPtr a_OnAllChunksAvailable);
protected:
/** The plugin which has created the ChunkStay, via cWorld:ChunkStay() binding method. */
@@ -49,10 +49,10 @@ protected:
cLuaState * m_LuaState;
/** The Lua function to call in OnChunkAvailable. Only valid when enabled. */
- cLuaState::cRef m_OnChunkAvailable;
+ cLuaState::cCallbackPtr m_OnChunkAvailable;
/** The Lua function to call in OnAllChunksAvailable. Only valid when enabled. */
- cLuaState::cRef m_OnAllChunksAvailable;
+ cLuaState::cCallbackPtr m_OnAllChunksAvailable;
// cChunkStay overrides:
diff --git a/src/Bindings/LuaNameLookup.cpp b/src/Bindings/LuaNameLookup.cpp
index e52d8dbdc..3cbdbb5cf 100644
--- a/src/Bindings/LuaNameLookup.cpp
+++ b/src/Bindings/LuaNameLookup.cpp
@@ -12,7 +12,7 @@
cLuaNameLookup::cLuaNameLookup(const AString & a_Query, cPluginLua & a_Plugin, int a_CallbacksTableStackPos):
m_Plugin(a_Plugin),
- m_Callbacks(a_Plugin.GetLuaState(), a_CallbacksTableStackPos),
+ m_Callbacks(cPluginLua::cOperation(a_Plugin)(), a_CallbacksTableStackPos),
m_Query(a_Query)
{
}
diff --git a/src/Bindings/LuaServerHandle.cpp b/src/Bindings/LuaServerHandle.cpp
index a84f894b5..9cc8ad350 100644
--- a/src/Bindings/LuaServerHandle.cpp
+++ b/src/Bindings/LuaServerHandle.cpp
@@ -14,7 +14,7 @@
cLuaServerHandle::cLuaServerHandle(UInt16 a_Port, cPluginLua & a_Plugin, int a_CallbacksTableStackPos):
m_Plugin(a_Plugin),
- m_Callbacks(a_Plugin.GetLuaState(), a_CallbacksTableStackPos),
+ m_Callbacks(cPluginLua::cOperation(a_Plugin)(), a_CallbacksTableStackPos),
m_Port(a_Port)
{
}
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index f11e74e75..5e6c24365 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -20,6 +20,10 @@ extern "C"
#include "../Entities/Entity.h"
#include "../BlockEntities/BlockEntity.h"
+
+
+
+
// fwd: "SQLite/lsqlite3.c"
extern "C"
{
@@ -39,6 +43,10 @@ extern "C"
const cLuaState::cRet cLuaState::Return = {};
+/** Each Lua state stores a pointer to its creating cLuaState in Lua globals, under this name.
+This way any cLuaState can reference the main cLuaState's TrackedCallbacks, mutex etc. */
+static const char * g_CanonLuaStateGlobalName = "_CuberiteInternal_CanonLuaState";
+
@@ -114,6 +122,135 @@ cLuaStateTracker & cLuaStateTracker::Get(void)
////////////////////////////////////////////////////////////////////////////////
+// cLuaState::cCallback:
+
+cLuaState::cCallback::cCallback(void):
+ m_CS(nullptr)
+{
+}
+
+
+
+
+
+bool cLuaState::cCallback::RefStack(cLuaState & a_LuaState, int a_StackPos)
+{
+ // Check if the stack contains a function:
+ if (!lua_isfunction(a_LuaState, a_StackPos))
+ {
+ return false;
+ }
+
+ // Clear any previous callback:
+ Clear();
+
+ // Add self to LuaState's callback-tracking:
+ auto canonState = a_LuaState.QueryCanonLuaState();
+ canonState->TrackCallback(*this);
+
+ // Store the new callback:
+ m_CS = &(canonState->m_CS);
+ m_Ref.RefStack(*canonState, a_StackPos);
+ return true;
+}
+
+
+
+
+
+void cLuaState::cCallback::Clear(void)
+{
+ // Free the callback reference:
+ lua_State * luaState = nullptr;
+ {
+ auto cs = m_CS;
+ if (cs != nullptr)
+ {
+ cCSLock Lock(*cs);
+ if (!m_Ref.IsValid())
+ {
+ return;
+ }
+ luaState = m_Ref.GetLuaState();
+ m_Ref.UnRef();
+ }
+ }
+
+ // Remove from LuaState's callback-tracking:
+ if (luaState == nullptr)
+ {
+ return;
+ }
+ cLuaState(luaState).UntrackCallback(*this);
+}
+
+
+
+
+
+bool cLuaState::cCallback::IsValid(void)
+{
+ auto cs = m_CS;
+ if (cs == nullptr)
+ {
+ return false;
+ }
+ cCSLock lock(*cs);
+ return m_Ref.IsValid();
+}
+
+
+
+
+
+bool cLuaState::cCallback::IsSameLuaState(cLuaState & a_LuaState)
+{
+ auto cs = m_CS;
+ if (cs == nullptr)
+ {
+ return false;
+ }
+ cCSLock lock(*cs);
+ if (!m_Ref.IsValid())
+ {
+ return false;
+ }
+ auto canonState = a_LuaState.QueryCanonLuaState();
+ if (canonState == nullptr)
+ {
+ return false;
+ }
+ return (m_Ref.GetLuaState() == static_cast<lua_State *>(*canonState));
+}
+
+
+
+
+
+void cLuaState::cCallback::Invalidate(void)
+{
+ auto cs = m_CS;
+ if (cs == nullptr)
+ {
+ // Already invalid
+ return;
+ }
+ cCSLock Lock(*cs);
+ if (!m_Ref.IsValid())
+ {
+ LOGD("%s: Inconsistent callback at %p, has a CS but an invalid Ref. This should not happen",
+ __FUNCTION__, reinterpret_cast<void *>(this)
+ );
+ return;
+ }
+ m_Ref.UnRef();
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
// cLuaState:
cLuaState::cLuaState(const AString & a_SubsystemName) :
@@ -170,6 +307,10 @@ void cLuaState::Create(void)
luaL_openlibs(m_LuaState);
m_IsOwned = true;
cLuaStateTracker::Add(*this);
+
+ // Add the CanonLuaState value into the Lua state, so that we can get it from anywhere:
+ lua_pushlightuserdata(m_LuaState, reinterpret_cast<void *>(this));
+ lua_setglobal(m_LuaState, g_CanonLuaStateGlobalName);
}
@@ -206,6 +347,16 @@ void cLuaState::Close(void)
Detach();
return;
}
+
+ // Invalidate all callbacks:
+ {
+ cCSLock Lock(m_CSTrackedCallbacks);
+ for (auto & c: m_TrackedCallbacks)
+ {
+ c->Invalidate();
+ }
+ }
+
cLuaStateTracker::Del(*this);
lua_close(m_LuaState);
m_LuaState = nullptr;
@@ -402,7 +553,7 @@ bool cLuaState::PushFunction(const char * a_FunctionName)
-bool cLuaState::PushFunction(int a_FnRef)
+bool cLuaState::PushFunction(const cRef & a_FnRef)
{
ASSERT(IsValid());
ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack
@@ -410,7 +561,7 @@ bool cLuaState::PushFunction(int a_FnRef)
// Push the error handler for lua_pcall()
lua_pushcfunction(m_LuaState, &ReportFnCallErrors);
- lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // same as lua_getref()
+ lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, static_cast<int>(a_FnRef)); // same as lua_getref()
if (!lua_isfunction(m_LuaState, -1))
{
lua_pop(m_LuaState, 2);
@@ -821,6 +972,18 @@ void cLuaState::Push(std::chrono::milliseconds a_Value)
+void cLuaState::Pop(int a_NumValuesToPop)
+{
+ ASSERT(IsValid());
+
+ lua_pop(m_LuaState, a_NumValuesToPop);
+ m_NumCurrentFunctionArgs -= a_NumValuesToPop;
+}
+
+
+
+
+
bool cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
{
size_t len = 0;
@@ -847,6 +1010,41 @@ bool cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal)
+bool cLuaState::GetStackValue(int a_StackPos, cCallback & a_Callback)
+{
+ return a_Callback.RefStack(*this, a_StackPos);
+}
+
+
+
+
+
+bool cLuaState::GetStackValue(int a_StackPos, cCallbackPtr & a_Callback)
+{
+ if (a_Callback == nullptr)
+ {
+ a_Callback = cpp14::make_unique<cCallback>();
+ }
+ return a_Callback->RefStack(*this, a_StackPos);
+}
+
+
+
+
+
+bool cLuaState::GetStackValue(int a_StackPos, cCallbackSharedPtr & a_Callback)
+{
+ if (a_Callback == nullptr)
+ {
+ a_Callback = std::make_shared<cCallback>();
+ }
+ return a_Callback->RefStack(*this, a_StackPos);
+}
+
+
+
+
+
bool cLuaState::GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result)
{
if (lua_isnumber(m_LuaState, a_StackPos))
@@ -1632,16 +1830,16 @@ void cLuaState::ToString(int a_StackPos, AString & a_String)
-void cLuaState::LogStack(const char * a_Header)
+void cLuaState::LogStackValues(const char * a_Header)
{
- LogStack(m_LuaState, a_Header);
+ LogStackValues(m_LuaState, a_Header);
}
-void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
+void cLuaState::LogStackValues(lua_State * a_LuaState, const char * a_Header)
{
// Format string consisting only of %s is used to appease the compiler
LOG("%s", (a_Header != nullptr) ? a_Header : "Lua C API Stack contents:");
@@ -1667,6 +1865,21 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
+cLuaState * cLuaState::QueryCanonLuaState(void)
+{
+ // Get the CanonLuaState global from Lua:
+ auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName);
+ if (!cb.IsValid())
+ {
+ return nullptr;
+ }
+ return reinterpret_cast<cLuaState *>(lua_touserdata(m_LuaState, -1));
+}
+
+
+
+
+
int cLuaState::ReportFnCallErrors(lua_State * a_LuaState)
{
LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1));
@@ -1701,6 +1914,50 @@ int cLuaState::BreakIntoDebugger(lua_State * a_LuaState)
+void cLuaState::TrackCallback(cCallback & a_Callback)
+{
+ // Get the CanonLuaState global from Lua:
+ auto canonState = QueryCanonLuaState();
+ if (canonState == nullptr)
+ {
+ LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast<void *>(m_LuaState));
+ return;
+ }
+
+ // Add the callback:
+ cCSLock Lock(canonState->m_CSTrackedCallbacks);
+ canonState->m_TrackedCallbacks.push_back(&a_Callback);
+}
+
+
+
+
+
+void cLuaState::UntrackCallback(cCallback & a_Callback)
+{
+ // Get the CanonLuaState global from Lua:
+ auto canonState = QueryCanonLuaState();
+ if (canonState == nullptr)
+ {
+ LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast<void *>(m_LuaState));
+ return;
+ }
+
+ // Remove the callback:
+ cCSLock Lock(canonState->m_CSTrackedCallbacks);
+ auto & trackedCallbacks = canonState->m_TrackedCallbacks;
+ trackedCallbacks.erase(std::remove_if(trackedCallbacks.begin(), trackedCallbacks.end(),
+ [&a_Callback](cCallback * a_StoredCallback)
+ {
+ return (a_StoredCallback == &a_Callback);
+ }
+ ));
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// cLuaState::cRef:
@@ -1756,7 +2013,7 @@ void cLuaState::cRef::RefStack(cLuaState & a_LuaState, int a_StackPos)
{
UnRef();
}
- m_LuaState = &a_LuaState;
+ m_LuaState = a_LuaState;
lua_pushvalue(a_LuaState, a_StackPos); // Push a copy of the value at a_StackPos onto the stack
m_Ref = luaL_ref(a_LuaState, LUA_REGISTRYINDEX);
}
@@ -1767,11 +2024,9 @@ void cLuaState::cRef::RefStack(cLuaState & a_LuaState, int a_StackPos)
void cLuaState::cRef::UnRef(void)
{
- ASSERT(m_LuaState->IsValid()); // The reference should be destroyed before destroying the LuaState
-
if (IsValid())
{
- luaL_unref(*m_LuaState, LUA_REGISTRYINDEX, m_Ref);
+ luaL_unref(m_LuaState, LUA_REGISTRYINDEX, m_Ref);
}
m_LuaState = nullptr;
m_Ref = LUA_REFNIL;
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index b795a80d4..106d8a783 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -7,7 +7,7 @@
The contained lua_State can be either owned or attached.
Owned lua_State is created by calling Create() and the cLuaState automatically closes the state
Or, lua_State can be attached by calling Attach(), the cLuaState doesn't close such a state
-Attaching a state will automatically close an owned state.
+If owning a state, trying to attach a state will automatically close the previously owned state.
Calling a Lua function is done internally by pushing the function using PushFunction(), then pushing the
arguments and finally executing CallFunction(). cLuaState automatically keeps track of the number of
@@ -16,8 +16,12 @@ the stack using GetStackValue(). All of this is wrapped in a templated function
which is generated automatically by gen_LuaState_Call.lua script file into the LuaState_Call.inc file.
Reference management is provided by the cLuaState::cRef class. This is used when you need to hold a reference to
-any Lua object across several function calls; usually this is used for callbacks. The class is RAII-like, with
-automatic resource management.
+any Lua object across several function calls. The class is RAII-like, with automatic resource management.
+
+Callbacks management is provided by the cLuaState::cCallback class. Use a GetStackValue() with cCallbackPtr
+parameter to store the callback, and then at any time you can use the cCallback's Call() templated function
+to call the callback. The callback management takes care of cLuaState being destroyed - the cCallback object
+stays valid but doesn't call into Lua code anymore, returning false for "failure" instead.
*/
@@ -39,6 +43,7 @@ extern "C"
class cLuaServerHandle;
class cLuaTCPLink;
class cLuaUDPEndpoint;
+class cPluginLua;
@@ -49,6 +54,20 @@ class cLuaState
{
public:
+ /** Provides a RAII-style locking for the LuaState.
+ Used mainly by the cPluginLua internals to provide the actual locking for interface operations, such as callbacks. */
+ class cLock
+ {
+ public:
+ cLock(cLuaState & a_LuaState):
+ m_Lock(a_LuaState.m_CS)
+ {
+ }
+ protected:
+ cCSLock m_Lock;
+ };
+
+
/** Used for storing references to object in the global registry.
Can be bound (contains a reference) or unbound (doesn't contain reference).
The reference can also be reset by calling RefStack(). */
@@ -80,8 +99,20 @@ public:
/** Allows to use this class wherever an int (i. e. ref) is to be used */
explicit operator int(void) const { return m_Ref; }
+ /** Returns the Lua state associated with the value. */
+ lua_State * GetLuaState(void) { return m_LuaState; }
+
+ /** Creates a Lua reference to the specified object instance in the specified Lua state.
+ This is useful to make anti-GC references for objects that were created by Lua and need to stay alive longer than Lua GC would normally guarantee. */
+ template <typename T> void CreateFromObject(cLuaState & a_LuaState, T && a_Object)
+ {
+ a_LuaState.Push(std::forward<T>(a_Object));
+ RefStack(a_LuaState, -1);
+ a_LuaState.Pop();
+ }
+
protected:
- cLuaState * m_LuaState;
+ lua_State * m_LuaState;
int m_Ref;
// Remove the copy-constructor:
@@ -112,6 +143,83 @@ public:
} ;
+ /** Represents a callback to Lua that C++ code can call.
+ Is thread-safe and unload-safe.
+ When the Lua state is unloaded, the callback returns an error instead of calling into non-existent code.
+ To receive the callback instance from the Lua side, use RefStack() or (better) cLuaState::GetStackValue()
+ with a cCallbackPtr. Note that instances of this class are tracked in the canon LuaState instance, so that
+ they can be invalidated when the LuaState is unloaded; due to multithreading issues they can only be tracked
+ by-ptr, which has an unfortunate effect of disabling the copy and move constructors. */
+ class cCallback
+ {
+ public:
+ /** Creates an unbound callback instance. */
+ cCallback(void);
+
+ ~cCallback()
+ {
+ Clear();
+ }
+
+ /** Calls the Lua callback, if still available.
+ Returns true if callback has been called.
+ Returns false if the Lua state isn't valid anymore. */
+ template <typename... Args>
+ bool Call(Args &&... args)
+ {
+ auto cs = m_CS;
+ if (cs == nullptr)
+ {
+ return false;
+ }
+ cCSLock Lock(*cs);
+ if (!m_Ref.IsValid())
+ {
+ return false;
+ }
+ return cLuaState(m_Ref.GetLuaState()).Call(m_Ref, std::forward<Args>(args)...);
+ }
+
+ /** Set the contained callback to the function in the specified Lua state's stack position.
+ If a callback has been previously contained, it is freed first. */
+ bool RefStack(cLuaState & a_LuaState, int a_StackPos);
+
+ /** Frees the contained callback, if any. */
+ void Clear(void);
+
+ /** Returns true if the contained callback is valid. */
+ bool IsValid(void);
+
+ /** Returns true if the callback resides in the specified Lua state.
+ Internally, compares the callback's canon Lua state. */
+ bool IsSameLuaState(cLuaState & a_LuaState);
+
+ protected:
+ friend class cLuaState;
+
+ /** The mutex protecting m_Ref against multithreaded access */
+ cCriticalSection * m_CS;
+
+ /** Reference to the Lua callback */
+ cRef m_Ref;
+
+
+ /** Invalidates the callback, without untracking it from the cLuaState.
+ Called only from cLuaState when closing the Lua state. */
+ void Invalidate(void);
+
+ /** This class cannot be copied, because it is tracked in the LuaState by-ptr.
+ Use cCallbackPtr for a copyable object. */
+ cCallback(const cCallback &) = delete;
+
+ /** This class cannot be moved, because it is tracked in the LuaState by-ptr.
+ Use cCallbackPtr for a copyable object. */
+ cCallback(cCallback &&) = delete;
+ };
+ typedef UniquePtr<cCallback> cCallbackPtr;
+ typedef SharedPtr<cCallback> cCallbackSharedPtr;
+
+
/** A dummy class that's used only to delimit function args from return values for cLuaState::Call() */
class cRet
{
@@ -168,6 +276,8 @@ public:
protected:
lua_State * m_LuaState;
+ /** Used for debugging, Lua state's stack size is checked against this number to make sure
+ it is the same as when the value was pushed. */
int m_StackLen;
// Remove the copy-constructor:
@@ -261,11 +371,17 @@ public:
void Push(const UInt32 a_Value);
void Push(std::chrono::milliseconds a_time);
+ /** Pops the specified number of values off the top of the Lua stack. */
+ void Pop(int a_NumValuesToPop = 1);
+
// GetStackValue() retrieves the value at a_StackPos, if it is a valid type. If not, a_Value is unchanged.
// Returns whether value was changed
// Enum values are checked for their allowed values and fail if the value is not assigned.
bool GetStackValue(int a_StackPos, AString & a_Value);
bool GetStackValue(int a_StackPos, bool & a_Value);
+ bool GetStackValue(int a_StackPos, cCallback & a_Callback);
+ bool GetStackValue(int a_StackPos, cCallbackPtr & a_Callback);
+ bool GetStackValue(int a_StackPos, cCallbackSharedPtr & a_Callback);
bool GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result);
bool GetStackValue(int a_StackPos, cRef & a_Ref);
bool GetStackValue(int a_StackPos, double & a_Value);
@@ -440,21 +556,26 @@ public:
void ToString(int a_StackPos, AString & a_String);
/** Logs all the elements' types on the API stack, with an optional header for the listing. */
- void LogStack(const char * a_Header = nullptr);
+ void LogStackValues(const char * a_Header = nullptr);
/** Logs all the elements' types on the API stack, with an optional header for the listing. */
- static void LogStack(lua_State * a_LuaState, const char * a_Header = nullptr);
+ static void LogStackValues(lua_State * a_LuaState, const char * a_Header = nullptr);
+
+ /** Returns the canon Lua state (the primary cLuaState instance that was used to create, rather than attach, the lua_State structure).
+ Returns nullptr if the canon Lua state cannot be queried. */
+ cLuaState * QueryCanonLuaState(void);
protected:
+ cCriticalSection m_CS;
+
lua_State * m_LuaState;
/** If true, the state is owned by this object and will be auto-Closed. False => attached state */
bool m_IsOwned;
/** The subsystem name is used for reporting errors to the console, it is either "plugin %s" or "LuaScript"
- whatever is given to the constructor
- */
+ whatever is given to the constructor. */
AString m_SubsystemName;
/** Name of the currently pushed function (for the Push / Call chain) */
@@ -463,6 +584,15 @@ protected:
/** Number of arguments currently pushed (for the Push / Call chain) */
int m_NumCurrentFunctionArgs;
+ /** The tracked callbacks.
+ This object will invalidate all of these when it is about to be closed.
+ Protected against multithreaded access by m_CSTrackedCallbacks. */
+ std::vector<cCallback *> m_TrackedCallbacks;
+
+ /** Protects m_TrackedTallbacks against multithreaded access. */
+ cCriticalSection m_CSTrackedCallbacks;
+
+
/** Variadic template terminator: If there's nothing more to push / pop, just call the function.
Note that there are no return values either, because those are prefixed by a cRet value, so the arg list is never empty. */
bool PushCallPop(void)
@@ -512,18 +642,10 @@ protected:
*/
bool PushFunction(const char * a_FunctionName);
- /** Pushes a function that has been saved into the global registry, identified by a_FnRef.
- Returns true if successful. Logs a warning on failure
- */
- bool PushFunction(int a_FnRef);
-
/** Pushes a function that has been saved as a reference.
Returns true if successful. Logs a warning on failure
*/
- bool PushFunction(const cRef & a_FnRef)
- {
- return PushFunction(static_cast<int>(a_FnRef));
- }
+ bool PushFunction(const cRef & a_FnRef);
/** Pushes a function that is stored in a referenced table by name
Returns true if successful. Logs a warning on failure
@@ -545,6 +667,14 @@ protected:
/** Tries to break into the MobDebug debugger, if it is installed. */
static int BreakIntoDebugger(lua_State * a_LuaState);
+
+ /** Adds the specified callback to tracking.
+ The callback will be invalidated when this Lua state is about to be closed. */
+ void TrackCallback(cCallback & a_Callback);
+
+ /** Removes the specified callback from tracking.
+ The callback will no longer be invalidated when this Lua state is about to be closed. */
+ void UntrackCallback(cCallback & a_Callback);
} ;
diff --git a/src/Bindings/LuaTCPLink.cpp b/src/Bindings/LuaTCPLink.cpp
index deaba9d86..4b04a1c02 100644
--- a/src/Bindings/LuaTCPLink.cpp
+++ b/src/Bindings/LuaTCPLink.cpp
@@ -13,7 +13,7 @@
cLuaTCPLink::cLuaTCPLink(cPluginLua & a_Plugin, int a_CallbacksTableStackPos):
m_Plugin(a_Plugin),
- m_Callbacks(a_Plugin.GetLuaState(), a_CallbacksTableStackPos)
+ m_Callbacks(cPluginLua::cOperation(a_Plugin)(), a_CallbacksTableStackPos)
{
// Warn if the callbacks aren't valid:
if (!m_Callbacks.IsValid())
diff --git a/src/Bindings/LuaUDPEndpoint.cpp b/src/Bindings/LuaUDPEndpoint.cpp
index 8637eeb4e..ed8f4e87f 100644
--- a/src/Bindings/LuaUDPEndpoint.cpp
+++ b/src/Bindings/LuaUDPEndpoint.cpp
@@ -12,7 +12,7 @@
cLuaUDPEndpoint::cLuaUDPEndpoint(cPluginLua & a_Plugin, int a_CallbacksTableStackPos):
m_Plugin(a_Plugin),
- m_Callbacks(a_Plugin.GetLuaState(), a_CallbacksTableStackPos)
+ m_Callbacks(cPluginLua::cOperation(a_Plugin)(), a_CallbacksTableStackPos)
{
// Warn if the callbacks aren't valid:
if (!m_Callbacks.IsValid())
diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp
index 706397a27..6fffa7aac 100644
--- a/src/Bindings/LuaWindow.cpp
+++ b/src/Bindings/LuaWindow.cpp
@@ -15,14 +15,13 @@
////////////////////////////////////////////////////////////////////////////////
// cLuaWindow:
-cLuaWindow::cLuaWindow(cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title) :
- super(a_WindowType, a_Title),
+cLuaWindow::cLuaWindow(cLuaState & a_LuaState, cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title) :
+ Super(a_WindowType, a_Title),
m_Contents(a_SlotsX, a_SlotsY),
- m_Plugin(nullptr),
- m_LuaRef(LUA_REFNIL),
- m_OnClosingFnRef(LUA_REFNIL),
- m_OnSlotChangedFnRef(LUA_REFNIL)
+ m_LuaState(a_LuaState.QueryCanonLuaState())
{
+ ASSERT(m_LuaState != nullptr); // We must have a valid Lua state; this assert fails only if there was no Canon Lua state
+
m_Contents.AddListener(*this);
m_SlotAreas.push_back(new cSlotAreaItemGrid(m_Contents, *this));
@@ -67,62 +66,42 @@ cLuaWindow::~cLuaWindow()
-void cLuaWindow::SetLuaRef(cPluginLua * a_Plugin, int a_LuaRef)
+void cLuaWindow::SetOnClosing(cLuaState::cCallbackPtr && a_OnClosing)
{
- // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object
- ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin));
- ASSERT(m_LuaRef == LUA_REFNIL);
- m_Plugin = a_Plugin;
- m_LuaRef = a_LuaRef;
-}
-
-
-
+ // Only one Lua state can be a cLuaWindow object callback:
+ ASSERT(a_OnClosing->IsSameLuaState(*m_LuaState));
-
-bool cLuaWindow::IsLuaReferenced(void) const
-{
- return ((m_Plugin != nullptr) && (m_LuaRef != LUA_REFNIL));
+ // Store the new reference, releasing the old one if appropriate:
+ m_OnClosing = std::move(a_OnClosing);
}
-void cLuaWindow::SetOnClosing(cPluginLua * a_Plugin, int a_FnRef)
+void cLuaWindow::SetOnSlotChanged(cLuaState::cCallbackPtr && a_OnSlotChanged)
{
- // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object
- ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin));
+ // Only one Lua state can be a cLuaWindow object callback:
+ ASSERT(a_OnSlotChanged->IsSameLuaState(*m_LuaState));
- // If there already was a function, unreference it first
- if (m_OnClosingFnRef != LUA_REFNIL)
- {
- m_Plugin->Unreference(m_OnClosingFnRef);
- }
-
- // Store the new reference
- m_Plugin = a_Plugin;
- m_OnClosingFnRef = a_FnRef;
+ // Store the new reference, releasing the old one if appropriate:
+ m_OnSlotChanged = std::move(a_OnSlotChanged);
}
-void cLuaWindow::SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef)
+void cLuaWindow::OpenedByPlayer(cPlayer & a_Player)
{
- // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object
- ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin));
-
- // If there already was a function, unreference it first
- if (m_OnSlotChangedFnRef != LUA_REFNIL)
+ // If the first player is opening the window, create a Lua Reference to the window object so that Lua will not GC it until the last player closes the window:
+ if (m_PlayerCount == 0)
{
- m_Plugin->Unreference(m_OnSlotChangedFnRef);
+ m_LuaRef.CreateFromObject(*m_LuaState, this);
}
- // Store the new reference
- m_Plugin = a_Plugin;
- m_OnSlotChangedFnRef = a_FnRef;
+ ++m_PlayerCount;
+ Super::OpenedByPlayer(a_Player);
}
@@ -132,17 +111,27 @@ void cLuaWindow::SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef)
bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
{
// First notify the plugin through the registered callback:
- if (m_OnClosingFnRef != LUA_REFNIL)
+ if (m_OnClosing != nullptr)
{
- ASSERT(m_Plugin != nullptr);
- if (m_Plugin->CallbackWindowClosing(m_OnClosingFnRef, *this, a_Player, a_CanRefuse))
+ bool res;
+ if (
+ m_OnClosing->Call(this, &a_Player, a_CanRefuse, cLuaState::Return, res) && // The callback succeeded
+ res // The callback says not to close the window
+ )
{
// The callback disagrees (the higher levels check the CanRefuse flag compliance)
return false;
}
}
- return super::ClosedByPlayer(a_Player, a_CanRefuse);
+ // If the last player has closed the window, release the Lua reference, so that Lua may GC the object:
+ --m_PlayerCount;
+ if (m_PlayerCount == 0)
+ {
+ m_LuaRef.UnRef();
+ }
+
+ return Super::ClosedByPlayer(a_Player, a_CanRefuse);
}
@@ -151,13 +140,7 @@ bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
void cLuaWindow::Destroy(void)
{
- super::Destroy();
-
- if ((m_LuaRef != LUA_REFNIL) && (m_Plugin != nullptr))
- {
- // The object is referenced by Lua, un-reference it
- m_Plugin->Unreference(m_LuaRef);
- }
+ Super::Destroy();
// Lua will take care of this object, it will garbage-collect it, so we must not delete it!
m_IsDestroyed = false;
@@ -178,7 +161,7 @@ void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Pl
}
}
- super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false);
+ Super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false);
}
@@ -194,9 +177,9 @@ void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
}
// If an OnSlotChanged callback has been registered, call it:
- if (m_OnSlotChangedFnRef != LUA_REFNIL)
+ if (m_OnSlotChanged != nullptr)
{
- m_Plugin->CallbackWindowSlotChanged(m_OnSlotChangedFnRef, *this, a_SlotNum);
+ m_OnSlotChanged->Call(this, a_SlotNum);
}
}
diff --git a/src/Bindings/LuaWindow.h b/src/Bindings/LuaWindow.h
index f292a5154..5f987d4c6 100644
--- a/src/Bindings/LuaWindow.h
+++ b/src/Bindings/LuaWindow.h
@@ -9,6 +9,8 @@
#pragma once
+#include <atomic>
+#include "LuaState.h"
#include "../UI/Window.h"
#include "../ItemGrid.h"
@@ -16,35 +18,30 @@
-// fwd: PluginLua.h
-class cPluginLua;
-
-
-
-
-
/** A window that has been created by a Lua plugin and is handled entirely by that plugin
This object needs extra care with its lifetime management:
- It is created by Lua, so Lua expects to garbage-collect it later
-- normal cWindow objects are deleted in their ClosedByPlayer() function if the last player closes them
-To overcome this, this object overloads the Destroy functions, which doesn't let the ClosedByPlayer()
-delete the window, but rather leaves it dangling, with only Lua having the reference to it.
-Additionally, to forbid Lua from deleting this object while it is used by players, the manual bindings for
-cPlayer:OpenWindow check if the window is of this class, and if so, make a global Lua reference for this object.
-This reference needs to be unreferenced in the Destroy() function. */
+- Normal cWindow objects are deleted in their ClosedByPlayer() function if the last player closes them
+ To overcome this, this object overloads the Destroy functions, which doesn't let the ClosedByPlayer()
+ delete the window, but rather leaves it dangling, with only Lua having the reference to it.
+- Lua could GC the window while a player is still using it
+ The object creates a Lua reference to itself when opened by a player and
+ removes the reference when the last player closes the window.
+*/
// tolua_begin
class cLuaWindow :
public cWindow
// tolua_end
, public cItemGrid::cListener
- // tolua_begin
-{
- typedef cWindow super;
+{ // tolua_export
+ typedef cWindow Super;
public:
- /** Create a window of the specified type, with a slot grid of a_SlotsX * a_SlotsY size */
- cLuaWindow(cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title);
+ /** Create a window of the specified type, with a slot grid of a_SlotsX * a_SlotsY size.
+ Exported in ManualBindings.cpp */
+ cLuaWindow(cLuaState & a_LuaState, cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title);
+ // tolua_begin
virtual ~cLuaWindow();
/** Returns the internal representation of the contents that are manipulated by Lua */
@@ -52,36 +49,37 @@ public:
// tolua_end
- /** Sets the plugin reference and the internal Lua object reference index
- used for preventing Lua's GC to collect this class while the window is open. */
- void SetLuaRef(cPluginLua * a_Plugin, int a_LuaRef);
-
- /** Returns true if SetLuaRef() has been called */
- bool IsLuaReferenced(void) const;
-
- /** Sets the callback function (Lua reference) to call when the window is about to close */
- void SetOnClosing(cPluginLua * a_Plugin, int a_FnRef);
+ /** Sets the Lua callback function to call when the window is about to close */
+ void SetOnClosing(cLuaState::cCallbackPtr && a_OnClosing);
- /** Sets the callback function (Lua reference) to call when a slot is changed */
- void SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef);
+ /** Sets the Lua callback function to call when a slot is changed */
+ void SetOnSlotChanged(cLuaState::cCallbackPtr && a_OnSlotChanged);
protected:
+
/** Contents of the non-inventory part */
cItemGrid m_Contents;
- /** The plugin that has opened the window and owns the m_LuaRef */
- cPluginLua * m_Plugin;
+ /** The Lua state that has opened the window and owns the m_LuaRef */
+ cLuaState * m_LuaState;
+
+ /** The Lua callback to call when the window is closing for any player */
+ cLuaState::cCallbackPtr m_OnClosing;
+
+ /** The Lua callback to call when a slot has changed */
+ cLuaState::cCallbackPtr m_OnSlotChanged;
- /** The Lua object reference, used for keeping the object alive as long as any player has the window open */
- int m_LuaRef;
+ /** Number of players that are currently using the window.
+ Used to manager the m_LuaRef lifetime. */
+ std::atomic<int> m_PlayerCount;
- /** The Lua reference for the callback to call when the window is closing for any player */
- int m_OnClosingFnRef;
+ /** Reference to self, to keep Lua from GCing the object while a player is still using it.
+ Created when the first player opens the window, destroyed when the last player closes the window. */
+ cLuaState::cRef m_LuaRef;
- /** The Lua reference for the callback to call when a slot has changed */
- int m_OnSlotChangedFnRef;
// cWindow overrides:
+ virtual void OpenedByPlayer(cPlayer & a_Player) override;
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
virtual void Destroy(void) override;
virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 9945929d0..1d735ac83 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -43,6 +43,50 @@
+////////////////////////////////////////////////////////////////////////////////
+// LuaCommandHandler:
+
+/** Defines a bridge between cPluginManager::cCommandHandler and cLuaState::cCallback. */
+class LuaCommandHandler:
+ public cPluginManager::cCommandHandler
+{
+public:
+ LuaCommandHandler(cLuaState::cCallbackPtr && a_Callback):
+ m_Callback(std::move(a_Callback))
+ {
+ }
+
+ virtual bool ExecuteCommand(
+ const AStringVector & a_Split,
+ cPlayer * a_Player,
+ const AString & a_Command,
+ cCommandOutputCallback * a_Output
+ ) override
+ {
+ bool res = false;
+ AString s;
+ if (!m_Callback->Call(a_Split, a_Player, a_Command, cLuaState::Return, res, s))
+ {
+ return false;
+ }
+ if (res && (a_Output != nullptr) && !s.empty())
+ {
+ a_Output->Out(s);
+ }
+ return res;
+ }
+
+protected:
+ cLuaState::cCallbackPtr m_Callback;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cManualBindings:
+
// Better error reporting for Lua
int cManualBindings::tolua_do_error(lua_State * L, const char * a_pMsg, tolua_Error * a_pToLuaError)
{
@@ -993,7 +1037,13 @@ static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager,
}
// Retrieve and check the hook type
- int HookType = static_cast<int>(tolua_tonumber(S, a_ParamIdx, -1));
+ int HookType;
+ if (!S.GetStackValue(a_ParamIdx, HookType))
+ {
+ LOGWARNING("cPluginManager.AddHook(): Cannot read the hook type.");
+ S.LogStackTrace();
+ return 0;
+ }
if (!a_PluginManager->IsValidHookType(HookType))
{
LOGWARNING("cPluginManager.AddHook(): Invalid HOOK_TYPE parameter: %d", HookType);
@@ -1002,7 +1052,14 @@ static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager,
}
// Add the hook to the plugin
- if (!Plugin->AddHookRef(HookType, a_ParamIdx + 1))
+ cLuaState::cCallbackPtr callback;
+ if (!S.GetStackValue(a_ParamIdx + 1, callback))
+ {
+ LOGWARNING("cPluginManager.AddHook(): Cannot read the callback parameter");
+ S.LogStackTrace();
+ return 0;
+ }
+ if (!Plugin->AddHookCallback(HookType, std::move(callback)))
{
LOGWARNING("cPluginManager.AddHook(): Cannot add hook %d, unknown error.", HookType);
S.LogStackTrace();
@@ -1059,10 +1116,11 @@ static int tolua_cPluginManager_AddHook_DefFn(cPluginManager * a_PluginManager,
}
// Retrieve the function to call and add it to the plugin:
- lua_pushstring(S, FnName);
- bool res = Plugin->AddHookRef(HookType, 1);
- lua_pop(S, 1); // Pop the function off the stack
- if (!res)
+ cLuaState::cCallbackPtr callback;
+ lua_getglobal(S, FnName);
+ bool res = S.GetStackValue(-1, callback);
+ lua_pop(S, 1);
+ if (!res || !callback->IsValid())
{
LOGWARNING("cPluginManager.AddHook(): Function %s not found. Hook not added.", FnName);
S.LogStackTrace();
@@ -1254,12 +1312,13 @@ static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S)
-static int tolua_cPluginManager_BindCommand(lua_State * L)
+static int tolua_cPluginManager_BindCommand(lua_State * a_LuaState)
{
/* Function signatures:
cPluginManager:BindCommand(Command, Permission, Function, HelpString)
cPluginManager.BindCommand(Command, Permission, Function, HelpString) -- without the "self" param
*/
+ cLuaState L(a_LuaState);
cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L);
if (Plugin == nullptr)
{
@@ -1292,29 +1351,24 @@ static int tolua_cPluginManager_BindCommand(lua_State * L)
return 0;
}
cPluginManager * self = cPluginManager::Get();
- AString Command (tolua_tocppstring(L, idx, ""));
- AString Permission(tolua_tocppstring(L, idx + 1, ""));
- AString HelpString(tolua_tocppstring(L, idx + 3, ""));
-
- // Store the function reference:
- lua_pop(L, 1); // Pop the help string off the stack
- int FnRef = luaL_ref(L, LUA_REGISTRYINDEX); // Store function reference
- if (FnRef == LUA_REFNIL)
+ AString Command, Permission, HelpString;
+ cLuaState::cCallbackPtr Handler;
+ L.GetStackValues(idx, Command, Permission, Handler, HelpString);
+ if (!Handler->IsValid())
{
LOGERROR("\"BindCommand\": Cannot create a function reference. Command \"%s\" not bound.", Command.c_str());
return 0;
}
- if (!self->BindCommand(Command, Plugin, Permission, HelpString))
+ auto CommandHandler = std::make_shared<LuaCommandHandler>(std::move(Handler));
+ if (!self->BindCommand(Command, Plugin, CommandHandler, Permission, HelpString))
{
// Refused. Possibly already bound. Error message has been given, display the callstack:
- cLuaState LS(L);
- LS.LogStackTrace();
+ L.LogStackTrace();
return 0;
}
- Plugin->BindCommand(Command, FnRef);
- lua_pushboolean(L, true);
+ L.Push(true);
return 1;
}
@@ -1322,7 +1376,7 @@ static int tolua_cPluginManager_BindCommand(lua_State * L)
-static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
+static int tolua_cPluginManager_BindConsoleCommand(lua_State * a_LuaState)
{
/* Function signatures:
cPluginManager:BindConsoleCommand(Command, Function, HelpString)
@@ -1330,6 +1384,7 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
*/
// Get the plugin identification out of LuaState:
+ cLuaState L(a_LuaState);
cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L);
if (Plugin == nullptr)
{
@@ -1361,28 +1416,23 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
return 0;
}
cPluginManager * self = cPluginManager::Get();
- AString Command (tolua_tocppstring(L, idx, ""));
- AString HelpString(tolua_tocppstring(L, idx + 2, ""));
-
- // Store the function reference:
- lua_pop(L, 1); // Pop the help string off the stack
- int FnRef = luaL_ref(L, LUA_REGISTRYINDEX); // Store function reference
- if (FnRef == LUA_REFNIL)
+ AString Command, HelpString;
+ cLuaState::cCallbackPtr Handler;
+ L.GetStackValues(idx, Command, Handler, HelpString);
+ if (!Handler->IsValid())
{
- LOGERROR("\"BindConsoleCommand\": Cannot create a function reference. Console Command \"%s\" not bound.", Command.c_str());
+ LOGERROR("\"BindConsoleCommand\": Cannot create a function reference. Console command \"%s\" not bound.", Command.c_str());
return 0;
}
- if (!self->BindConsoleCommand(Command, Plugin, HelpString))
+ auto CommandHandler = std::make_shared<LuaCommandHandler>(std::move(Handler));
+ if (!self->BindConsoleCommand(Command, Plugin, CommandHandler, HelpString))
{
// Refused. Possibly already bound. Error message has been given, display the callstack:
- cLuaState LS(L);
- LS.LogStackTrace();
+ L.LogStackTrace();
return 0;
}
-
- Plugin->BindConsoleCommand(Command, FnRef);
- lua_pushboolean(L, true);
+ L.Push(true);
return 1;
}
@@ -1586,55 +1636,6 @@ static int tolua_cPlayer_GetRestrictions(lua_State * tolua_S)
-static int tolua_cPlayer_OpenWindow(lua_State * tolua_S)
-{
- // Function signature: cPlayer:OpenWindow(Window)
-
- // Retrieve the plugin instance from the Lua state
- cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S);
- if (Plugin == nullptr)
- {
- return 0;
- }
-
- // Get the parameters:
- cPlayer * self = reinterpret_cast<cPlayer *>(tolua_tousertype(tolua_S, 1, nullptr));
- cWindow * wnd = reinterpret_cast<cWindow *>(tolua_tousertype(tolua_S, 2, nullptr));
- if ((self == nullptr) || (wnd == nullptr))
- {
- LOGWARNING("%s: invalid self (%p) or wnd (%p)", __FUNCTION__, static_cast<void *>(self), static_cast<void *>(wnd));
- return 0;
- }
-
- // If cLuaWindow, add a reference, so that Lua won't delete the cLuaWindow object mid-processing
- tolua_Error err;
- if (tolua_isusertype(tolua_S, 2, "cLuaWindow", 0, &err))
- {
- cLuaWindow * LuaWnd = reinterpret_cast<cLuaWindow *>(wnd);
- // Only if not already referenced
- if (!LuaWnd->IsLuaReferenced())
- {
- int LuaRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
- if (LuaRef == LUA_REFNIL)
- {
- LOGWARNING("%s: Cannot create a window reference. Cannot open window \"%s\".",
- __FUNCTION__, wnd->GetWindowTitle().c_str()
- );
- return 0;
- }
- LuaWnd->SetLuaRef(Plugin, LuaRef);
- }
- }
-
- // Open the window
- self->OpenWindow(wnd);
- return 0;
-}
-
-
-
-
-
static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S)
{
// Function signature: cPlayer:PermissionMatches(PermissionStr, TemplateStr) -> bool
@@ -1665,36 +1666,25 @@ static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S)
template <
class OBJTYPE,
- void (OBJTYPE::*SetCallback)(cPluginLua * a_Plugin, int a_FnRef)
+ void (OBJTYPE::*SetCallback)(cLuaState::cCallbackPtr && a_CallbackFn)
>
static int tolua_SetObjectCallback(lua_State * tolua_S)
{
// Function signature: OBJTYPE:SetWhateverCallback(CallbackFunction)
- // Retrieve the plugin instance from the Lua state
- cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S);
- if (Plugin == nullptr)
- {
- // Warning message has already been printed by GetLuaPlugin(), bail out silently
- return 0;
- }
-
// Get the parameters - self and the function reference:
- OBJTYPE * self = reinterpret_cast<OBJTYPE *>(tolua_tousertype(tolua_S, 1, nullptr));
- if (self == nullptr)
- {
- LOGWARNING("%s: invalid self (%p)", __FUNCTION__, static_cast<void *>(self));
- return 0;
- }
- int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); // Store function reference for later retrieval
- if (FnRef == LUA_REFNIL)
+ cLuaState L(tolua_S);
+ OBJTYPE * self;
+ cLuaState::cCallbackPtr callback;
+ if (!L.GetStackValues(1, self, callback))
{
- LOGERROR("%s: Cannot create a function reference. Callback not set.", __FUNCTION__);
+ LOGWARNING("%s: Cannot get parameters", __FUNCTION__);
+ L.LogStackTrace();
return 0;
}
// Set the callback
- (self->*SetCallback)(Plugin, FnRef);
+ (self->*SetCallback)(std::move(callback));
return 0;
}
@@ -1702,47 +1692,71 @@ static int tolua_SetObjectCallback(lua_State * tolua_S)
-static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S)
+// Callback class used for the WebTab:
+class cWebTabCallback:
+ public cWebAdmin::cWebTabCallback
{
- cLuaState LuaState(tolua_S);
- cPluginLua * self = nullptr;
+public:
+ /** The Lua callback to call to generate the page contents. */
+ cLuaState::cCallback m_Callback;
- if (!LuaState.GetStackValue(1, self))
+ virtual bool Call(
+ const HTTPRequest & a_Request,
+ const AString & a_UrlPath,
+ AString & a_Content,
+ AString & a_ContentType
+ ) override
{
- LOGWARNING("cPluginLua:AddWebTab: invalid self as first argument");
- return 0;
+ AString content, contentType;
+ return m_Callback.Call(&a_Request, a_UrlPath, cLuaState::Return, a_Content, a_ContentType);
}
+};
+
+
+
- tolua_Error tolua_err;
- tolua_err.array = 0;
- tolua_err.index = 3;
- tolua_err.type = "function";
- std::string Title;
- int Reference = LUA_REFNIL;
+static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S)
+{
+ // OBSOLETE, use cWebAdmin:AddWebTab() instead!
+ // Function signature:
+ // cPluginLua:AddWebTab(Title, CallbackFn, [UrlPath])
- if (LuaState.CheckParamString(2) && LuaState.CheckParamFunction(3))
+ // TODO: Warn about obsolete API usage
+ // Only implement after merging the new API change and letting some time for changes in the plugins
+
+ // Check params:
+ cLuaState LuaState(tolua_S);
+ cPluginLua * self = cManualBindings::GetLuaPlugin(tolua_S);
+ if (self == nullptr)
{
- Reference = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
- LuaState.GetStackValue(2, Title);
+ return 0;
}
- else
+ if (
+ !LuaState.CheckParamString(2) ||
+ !LuaState.CheckParamFunction(3) ||
+ // Optional string as param 4
+ !LuaState.CheckParamEnd(5)
+ )
{
- return cManualBindings::tolua_do_error(tolua_S, "#ferror calling function '#funcname#'", &tolua_err);
+ return 0;
}
- if (Reference != LUA_REFNIL)
+ // Read the params:
+ AString title, urlPath;
+ auto callback = std::make_shared<cWebTabCallback>();
+ if (!LuaState.GetStackValues(2, title, callback->m_Callback))
{
- if (!self->AddWebTab(Title.c_str(), tolua_S, Reference))
- {
- luaL_unref(tolua_S, LUA_REGISTRYINDEX, Reference);
- }
+ LOGWARNING("cPlugin:AddWebTab(): Cannot read required parameters");
+ return 0;
}
- else
+ if (!LuaState.GetStackValue(4, urlPath))
{
- LOGWARNING("cPluginLua:AddWebTab: invalid function reference in 2nd argument (Title: \"%s\")", Title.c_str());
+ urlPath = cWebAdmin::GetURLEncodedString(title);
}
+ cRoot::Get()->GetWebAdmin()->AddWebTab(title, urlPath, self->GetName(), callback);
+
return 0;
}
@@ -2107,22 +2121,68 @@ static int tolua_cUrlParser_ParseAuthorityPart(lua_State * a_LuaState)
-static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S)
+static int tolua_cWebAdmin_AddWebTab(lua_State * tolua_S)
+{
+ // Function signatures:
+ // cWebAdmin:AddWebTab(Title, UrlPath, CallbackFn)
+
+ // Check params:
+ cLuaState LuaState(tolua_S);
+ cPluginLua * self = cManualBindings::GetLuaPlugin(tolua_S);
+ if (self == nullptr)
+ {
+ return 0;
+ }
+ if (
+ // Don't care whether the first param is a cWebAdmin instance or class
+ !LuaState.CheckParamString(2, 3) ||
+ !LuaState.CheckParamFunction(4) ||
+ !LuaState.CheckParamEnd(5)
+ )
+ {
+ return 0;
+ }
+
+ // Read the params:
+ AString title, urlPath;
+ auto callback = std::make_shared<cWebTabCallback>();
+ if (!LuaState.GetStackValues(2, title, urlPath, callback->m_Callback))
+ {
+ LOGWARNING("cWebAdmin:AddWebTab(): Cannot read required parameters");
+ return 0;
+ }
+
+ cRoot::Get()->GetWebAdmin()->AddWebTab(title, urlPath, self->GetName(), callback);
+
+ return 0;
+}
+
+
+
+
+
+static int tolua_cWebAdmin_GetAllWebTabs(lua_State * tolua_S)
{
- cWebAdmin * self = reinterpret_cast<cWebAdmin *>(tolua_tousertype(tolua_S, 1, nullptr));
+ // Function signature:
+ // cWebAdmin:GetAllWebTabs() -> { {"PluginName", "UrlPath", "Title"}, {"PluginName", "UrlPath", "Title"}, ...}
- const cWebAdmin::PluginList & AllPlugins = self->GetPlugins();
+ // Don't care about params at all
- lua_createtable(tolua_S, static_cast<int>(AllPlugins.size()), 0);
+ auto webTabs = cRoot::Get()->GetWebAdmin()->GetAllWebTabs();
+ lua_createtable(tolua_S, static_cast<int>(webTabs.size()), 0);
int newTable = lua_gettop(tolua_S);
int index = 1;
- cWebAdmin::PluginList::const_iterator iter = AllPlugins.begin();
- while (iter != AllPlugins.end())
- {
- const cWebPlugin * Plugin = *iter;
- tolua_pushusertype(tolua_S, reinterpret_cast<void *>(const_cast<cWebPlugin*>(Plugin)), "const cWebPlugin");
+ cLuaState L(tolua_S);
+ for (const auto & wt: webTabs)
+ {
+ lua_createtable(tolua_S, 0, 3);
+ L.Push(wt->m_PluginName);
+ lua_setfield(tolua_S, -2, "PluginName");
+ L.Push(wt->m_UrlPath);
+ lua_setfield(tolua_S, -2, "UrlPath");
+ L.Push(wt->m_Title);
+ lua_setfield(tolua_S, -2, "Title");
lua_rawseti(tolua_S, newTable, index);
- ++iter;
++index;
}
return 1;
@@ -2132,14 +2192,14 @@ static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S)
-/** Binding for cWebAdmin::GetHTMLEscapedString.
+/** Binding for cWebAdmin::GetBaseURL.
Manual code required because ToLua generates an extra return value */
-static int tolua_AllToLua_cWebAdmin_GetHTMLEscapedString(lua_State * tolua_S)
+static int tolua_cWebAdmin_GetBaseURL(lua_State * tolua_S)
{
// Check the param types:
cLuaState S(tolua_S);
if (
- !S.CheckParamUserTable(1, "cWebAdmin") ||
+ // Don't care whether the first param is a cWebAdmin instance or class
!S.CheckParamString(2) ||
!S.CheckParamEnd(3)
)
@@ -2152,7 +2212,7 @@ static int tolua_AllToLua_cWebAdmin_GetHTMLEscapedString(lua_State * tolua_S)
S.GetStackValue(2, Input);
// Convert and return:
- S.Push(cWebAdmin::GetHTMLEscapedString(Input));
+ S.Push(cWebAdmin::GetBaseURL(Input));
return 1;
}
@@ -2160,14 +2220,14 @@ static int tolua_AllToLua_cWebAdmin_GetHTMLEscapedString(lua_State * tolua_S)
-/** Binding for cWebAdmin::GetURLEncodedString.
+/** Binding for cWebAdmin::GetContentTypeFromFileExt.
Manual code required because ToLua generates an extra return value */
-static int tolua_AllToLua_cWebAdmin_GetURLEncodedString(lua_State * tolua_S)
+static int tolua_cWebAdmin_GetContentTypeFromFileExt(lua_State * tolua_S)
{
// Check the param types:
cLuaState S(tolua_S);
if (
- !S.CheckParamUserTable(1, "cWebAdmin") ||
+ // Don't care whether the first param is a cWebAdmin instance or class
!S.CheckParamString(2) ||
!S.CheckParamEnd(3)
)
@@ -2180,7 +2240,7 @@ static int tolua_AllToLua_cWebAdmin_GetURLEncodedString(lua_State * tolua_S)
S.GetStackValue(2, Input);
// Convert and return:
- S.Push(cWebAdmin::GetURLEncodedString(Input));
+ S.Push(cWebAdmin::GetContentTypeFromFileExt(Input));
return 1;
}
@@ -2188,20 +2248,112 @@ static int tolua_AllToLua_cWebAdmin_GetURLEncodedString(lua_State * tolua_S)
-static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S)
+/** Binding for cWebAdmin::GetHTMLEscapedString.
+Manual code required because ToLua generates an extra return value */
+static int tolua_cWebAdmin_GetHTMLEscapedString(lua_State * tolua_S)
{
- // Returns a map of (SafeTitle -> Title) for the plugin's web tabs.
- auto self = reinterpret_cast<cWebPlugin *>(tolua_tousertype(tolua_S, 1, nullptr));
- auto TabNames = self->GetTabNames();
- lua_newtable(tolua_S);
- int index = 1;
- for (auto itr = TabNames.cbegin(), end = TabNames.cend(); itr != end; ++itr)
+ // Check the param types:
+ cLuaState S(tolua_S);
+ if (
+ // Don't care whether the first param is a cWebAdmin instance or class
+ !S.CheckParamString(2) ||
+ !S.CheckParamEnd(3)
+ )
{
- tolua_pushstring(tolua_S, itr->second.c_str()); // Because the SafeTitle is supposed to be unique, use it as key
- tolua_pushstring(tolua_S, itr->first.c_str());
- lua_rawset(tolua_S, -3);
- ++index;
+ return 0;
+ }
+
+ // Get the parameters:
+ AString Input;
+ S.GetStackValue(2, Input);
+
+ // Convert and return:
+ S.Push(cWebAdmin::GetHTMLEscapedString(Input));
+ return 1;
+}
+
+
+
+
+
+/** Binding for cWebAdmin::GetPage. */
+static int tolua_cWebAdmin_GetPage(lua_State * tolua_S)
+{
+ /*
+ Function signature:
+ cWebAdmin:GetPage(a_HTTPRequest) ->
+ {
+ Content = "", // Content generated by the plugin
+ ContentType = "", // Content type generated by the plugin (default: "text/html")
+ UrlPath = "", // URL path of the tab
+ TabTitle = "", // Tab's title, as register via cWebAdmin:AddWebTab()
+ PluginName = "", // Plugin's API name
+ PluginFolder = "", // Plugin's folder name (display name)
+ }
+ */
+
+ // Check the param types:
+ cLuaState S(tolua_S);
+ if (
+ // Don't care about first param, whether it's cWebAdmin instance or class
+ !S.CheckParamUserType(2, "HTTPRequest") ||
+ !S.CheckParamEnd(3)
+ )
+ {
+ return 0;
+ }
+
+ // Get the parameters:
+ HTTPRequest * request = nullptr;
+ if (!S.GetStackValue(2, request))
+ {
+ LOGWARNING("cWebAdmin:GetPage(): Cannot read the HTTPRequest parameter.");
+ return 0;
+ }
+
+ // Generate the page and push the results as a dictionary-table:
+ auto page = cRoot::Get()->GetWebAdmin()->GetPage(*request);
+ lua_createtable(S, 0, 6);
+ S.Push(page.Content);
+ lua_setfield(S, -2, "Content");
+ S.Push(page.ContentType);
+ lua_setfield(S, -2, "ContentType");
+ S.Push(page.TabUrlPath);
+ lua_setfield(S, -2, "UrlPath");
+ S.Push(page.TabTitle);
+ lua_setfield(S, -2, "TabTitle");
+ S.Push(page.PluginName);
+ lua_setfield(S, -2, "PluginName");
+ S.Push(cPluginManager::Get()->GetPluginFolderName(page.PluginName));
+ lua_setfield(S, -2, "PluginFolder");
+ return 1;
+}
+
+
+
+
+
+/** Binding for cWebAdmin::GetURLEncodedString.
+Manual code required because ToLua generates an extra return value */
+static int tolua_cWebAdmin_GetURLEncodedString(lua_State * tolua_S)
+{
+ // Check the param types:
+ cLuaState S(tolua_S);
+ if (
+ // Don't care whether the first param is a cWebAdmin instance or class
+ !S.CheckParamString(2) ||
+ !S.CheckParamEnd(3)
+ )
+ {
+ return 0;
}
+
+ // Get the parameters:
+ AString Input;
+ S.GetStackValue(2, Input);
+
+ // Convert and return:
+ S.Push(cWebAdmin::GetURLEncodedString(Input));
return 1;
}
@@ -2624,6 +2776,79 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
+static int tolua_cLuaWindow_new(lua_State * tolua_S)
+{
+ // Function signature:
+ // cLuaWindow:new(type, slotsX, slotsY, title)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserTable(1, "cLuaWindow") ||
+ !L.CheckParamNumber(2, 4) ||
+ !L.CheckParamString(5) ||
+ !L.CheckParamEnd(6)
+ )
+ {
+ return 0;
+ }
+
+ // Read params:
+ int windowType, slotsX, slotsY;
+ AString title;
+ if (!L.GetStackValues(2, windowType, slotsX, slotsY, title))
+ {
+ LOGWARNING("%s: Cannot read Lua parameters", __FUNCTION__);
+ L.LogStackValues();
+ L.LogStackTrace();
+ }
+
+ // Create the window and return it:
+ L.Push(new cLuaWindow(L, static_cast<cLuaWindow::WindowType>(windowType), slotsX, slotsY, title));
+ return 1;
+}
+
+
+
+
+
+static int tolua_cLuaWindow_new_local(lua_State * tolua_S)
+{
+ // Function signature:
+ // cLuaWindow:new(type, slotsX, slotsY, title)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserTable(1, "cLuaWindow") ||
+ !L.CheckParamNumber(2, 4) ||
+ !L.CheckParamString(5) ||
+ !L.CheckParamEnd(6)
+ )
+ {
+ return 0;
+ }
+
+ // Read params:
+ int windowType, slotsX, slotsY;
+ AString title;
+ if (!L.GetStackValues(2, windowType, slotsX, slotsY, title))
+ {
+ LOGWARNING("%s: Cannot read Lua parameters", __FUNCTION__);
+ L.LogStackValues();
+ L.LogStackTrace();
+ }
+
+ // Create the window, register it for GC and return it:
+ L.Push(new cLuaWindow(L, static_cast<cLuaWindow::WindowType>(windowType), slotsX, slotsY, title));
+ tolua_register_gc(tolua_S, lua_gettop(tolua_S));
+ return 1;
+}
+
+
+
+
+
static int tolua_cRoot_GetBuildCommitID(lua_State * tolua_S)
{
cLuaState L(tolua_S);
@@ -3167,7 +3392,7 @@ static int tolua_cBoundingBox_CalcLineIntersection(lua_State * a_LuaState)
const cBoundingBox * bbox;
if (!L.GetStackValues(1, bbox, pt1, pt2)) // Try the regular signature
{
- L.LogStack();
+ L.LogStackValues();
tolua_error(a_LuaState, "Invalid function params. Expected either bbox:CalcLineIntersection(pt1, pt2) or cBoundingBox:CalcLineIntersection(min, max, pt1, pt2).", nullptr);
return 0;
}
@@ -3197,7 +3422,7 @@ static int tolua_cBoundingBox_Intersect(lua_State * a_LuaState)
const cBoundingBox * other;
if (!L.GetStackValues(1, self, other))
{
- L.LogStack();
+ L.LogStackValues();
tolua_error(a_LuaState, "Invalid function params. Expected bbox:Intersect(otherBbox).", nullptr);
return 0;
}
@@ -3570,6 +3795,9 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cLuaWindow");
+ tolua_function(tolua_S, "new", tolua_cLuaWindow_new);
+ tolua_function(tolua_S, "new_local", tolua_cLuaWindow_new_local);
+ tolua_function(tolua_S, ".call", tolua_cLuaWindow_new_local);
tolua_function(tolua_S, "SetOnClosing", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClosing>);
tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnSlotChanged>);
tolua_endmodule(tolua_S);
@@ -3590,7 +3818,6 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_beginmodule(tolua_S, "cPlayer");
tolua_function(tolua_S, "GetPermissions", tolua_cPlayer_GetPermissions);
tolua_function(tolua_S, "GetRestrictions", tolua_cPlayer_GetRestrictions);
- tolua_function(tolua_S, "OpenWindow", tolua_cPlayer_OpenWindow);
tolua_function(tolua_S, "PermissionMatches", tolua_cPlayer_PermissionMatches);
tolua_endmodule(tolua_S);
@@ -3655,13 +3882,13 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cWebAdmin");
- tolua_function(tolua_S, "GetHTMLEscapedString", tolua_AllToLua_cWebAdmin_GetHTMLEscapedString);
- tolua_function(tolua_S, "GetPlugins", tolua_cWebAdmin_GetPlugins);
- tolua_function(tolua_S, "GetURLEncodedString", tolua_AllToLua_cWebAdmin_GetURLEncodedString);
- tolua_endmodule(tolua_S);
-
- tolua_beginmodule(tolua_S, "cWebPlugin");
- tolua_function(tolua_S, "GetTabNames", tolua_cWebPlugin_GetTabNames);
+ tolua_function(tolua_S, "AddWebTab", tolua_cWebAdmin_AddWebTab);
+ tolua_function(tolua_S, "GetAllWebTabs", tolua_cWebAdmin_GetAllWebTabs);
+ tolua_function(tolua_S, "GetBaseURL", tolua_cWebAdmin_GetBaseURL);
+ tolua_function(tolua_S, "GetContentTypeFromFileExt", tolua_cWebAdmin_GetContentTypeFromFileExt);
+ tolua_function(tolua_S, "GetHTMLEscapedString", tolua_cWebAdmin_GetHTMLEscapedString);
+ tolua_function(tolua_S, "GetPage", tolua_cWebAdmin_GetPage);
+ tolua_function(tolua_S, "GetURLEncodedString", tolua_cWebAdmin_GetURLEncodedString);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "HTTPRequest");
diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp
index 00d2169d8..b3170a636 100644
--- a/src/Bindings/ManualBindings_World.cpp
+++ b/src/Bindings/ManualBindings_World.cpp
@@ -103,7 +103,9 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
return 0;
}
- ChunkStay->Enable(*World->GetChunkMap(), 3, 4);
+ cLuaState::cCallbackPtr onChunkAvailable, onAllChunksAvailable;
+ L.GetStackValues(3, onChunkAvailable, onAllChunksAvailable); // Callbacks may be unassigned at all - as a request to load / generate chunks
+ ChunkStay->Enable(*World->GetChunkMap(), std::move(onChunkAvailable), std::move(onAllChunksAvailable));
return 0;
}
@@ -466,67 +468,41 @@ static int tolua_cWorld_PrepareChunk(lua_State * tolua_S)
-class cLuaWorldTask :
- public cPluginLua::cResettable
-{
-public:
- cLuaWorldTask(cPluginLua & a_Plugin, int a_FnRef) :
- cPluginLua::cResettable(a_Plugin),
- m_FnRef(a_FnRef)
- {
- }
-
- void Run(cWorld & a_World)
- {
- cCSLock Lock(m_CSPlugin);
- if (m_Plugin != nullptr)
- {
- m_Plugin->Call(m_FnRef, &a_World);
- }
- }
-
-protected:
- int m_FnRef;
-};
-
-
-
-
-
static int tolua_cWorld_QueueTask(lua_State * tolua_S)
{
- // Binding for cWorld::QueueTask
- // Params: function
+ // Function signature:
+ // World:QueueTask(Callback)
- // Retrieve the cPlugin from the LuaState:
- cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S);
- if (Plugin == nullptr)
+ // Retrieve the args:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cWorld") ||
+ !L.CheckParamNumber (2) ||
+ !L.CheckParamFunction(3)
+ )
{
- // An error message has been already printed in GetLuaPlugin()
return 0;
}
-
- // Retrieve the args:
- cWorld * self = reinterpret_cast<cWorld *>(tolua_tousertype(tolua_S, 1, nullptr));
- if (self == nullptr)
+ cWorld * World;
+ cLuaState::cCallbackSharedPtr Task;
+ if (!L.GetStackValues(1, World, Task))
{
- return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance");
+ return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Cannot read parameters");
}
- if (!lua_isfunction(tolua_S, 2))
+ if (World == nullptr)
{
- return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1");
+ return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance");
}
-
- // Create a reference to the function:
- int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
- if (FnRef == LUA_REFNIL)
+ if (!Task->IsValid())
{
- return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1");
+ return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not store the callback parameter");
}
- auto ResettableTask = std::make_shared<cLuaWorldTask>(*Plugin, FnRef);
- Plugin->AddResettable(ResettableTask);
- self->QueueTask(std::bind(&cLuaWorldTask::Run, ResettableTask, std::placeholders::_1));
+ World->QueueTask([Task](cWorld & a_World)
+ {
+ Task->Call(&a_World);
+ }
+ );
return 0;
}
@@ -576,16 +552,8 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S)
static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
{
- // Binding for cWorld::ScheduleTask
- // Params: function, Ticks
-
- // 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;
- }
+ // Function signature:
+ // World:ScheduleTask(NumTicks, Callback)
// Retrieve the args:
cLuaState L(tolua_S);
@@ -597,22 +565,27 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
{
return 0;
}
- cWorld * World = reinterpret_cast<cWorld *>(tolua_tousertype(tolua_S, 1, nullptr));
+ cWorld * World;
+ int NumTicks;
+ auto Task = std::make_shared<cLuaState::cCallback>();
+ if (!L.GetStackValues(1, World, NumTicks, Task))
+ {
+ return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Cannot read parameters");
+ }
if (World == nullptr)
{
return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance");
}
-
- // Create a reference to the function:
- int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
- if (FnRef == LUA_REFNIL)
+ if (!Task->IsValid())
{
- return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1");
+ return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not store the callback parameter");
}
- auto ResettableTask = std::make_shared<cLuaWorldTask>(*Plugin, FnRef);
- Plugin->AddResettable(ResettableTask);
- World->ScheduleTask(static_cast<int>(tolua_tonumber(tolua_S, 2, 0)), std::bind(&cLuaWorldTask::Run, ResettableTask, std::placeholders::_1));
+ World->ScheduleTask(NumTicks, [Task](cWorld & a_World)
+ {
+ Task->Call(&a_World);
+ }
+ );
return 0;
}
diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h
index 3ee417361..3276fde67 100644
--- a/src/Bindings/Plugin.h
+++ b/src/Bindings/Plugin.h
@@ -110,21 +110,6 @@ public:
virtual bool OnWorldStarted (cWorld & a_World) = 0;
virtual bool OnWorldTick (cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec) = 0;
- /** Handles the command split into a_Split, issued by player a_Player.
- Command permissions have already been checked.
- Returns true if command handled successfully. */
- virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand) = 0;
-
- /** Handles the console command split into a_Split.
- Returns true if command handled successfully. Output is to be sent to the a_Output callback. */
- virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand) = 0;
-
- /** All bound commands are to be removed, do any language-dependent cleanup here */
- virtual void ClearCommands(void) {}
-
- /** All bound console commands are to be removed, do any language-dependent cleanup here */
- virtual void ClearConsoleCommands(void) {}
-
// tolua_begin
const AString & GetName(void) const { return m_Name; }
void SetName(const AString & a_Name) { m_Name = a_Name; }
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index a266e6223..d1fc2ae4f 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -15,6 +15,8 @@
#include "../CommandOutput.h"
#include "PluginManager.h"
#include "../Item.h"
+#include "../Root.h"
+#include "../WebAdmin.h"
extern "C"
{
@@ -43,7 +45,6 @@ cPluginLua::cPluginLua(const AString & a_PluginDirectory) :
cPluginLua::~cPluginLua()
{
- cCSLock Lock(m_CriticalSection);
Close();
}
@@ -53,45 +54,22 @@ cPluginLua::~cPluginLua()
void cPluginLua::Close(void)
{
- cCSLock Lock(m_CriticalSection);
-
+ cOperation op(*this);
// If already closed, bail out:
- if (!m_LuaState.IsValid())
+ if (!op().IsValid())
{
- ASSERT(m_Resettables.empty());
ASSERT(m_HookMap.empty());
return;
}
- // Remove the command bindings and web tabs:
- ClearCommands();
- ClearConsoleCommands();
- ClearTabs();
-
- // Notify and remove all m_Resettables (unlock the m_CriticalSection while resetting them):
- cResettablePtrs resettables;
- std::swap(m_Resettables, resettables);
- {
- cCSUnlock Unlock(Lock);
- for (auto resettable: resettables)
- {
- resettable->Reset();
- }
- m_Resettables.clear();
- } // cCSUnlock (m_CriticalSection)
+ // Remove the web tabs:
+ ClearWebTabs();
// Release all the references in the hook map:
- for (cHookMap::iterator itrH = m_HookMap.begin(), endH = m_HookMap.end(); itrH != endH; ++itrH)
- {
- for (cLuaRefs::iterator itrR = itrH->second.begin(), endR = itrH->second.end(); itrR != endR; ++itrR)
- {
- delete *itrR;
- } // for itrR - itrH->second[]
- } // for itrH - m_HookMap[]
m_HookMap.clear();
// Close the Lua engine:
- m_LuaState.Close();
+ op().Close();
}
@@ -100,8 +78,8 @@ void cPluginLua::Close(void)
bool cPluginLua::Load(void)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
m_LuaState.Create();
m_LuaState.RegisterAPILibs();
@@ -205,7 +183,7 @@ bool cPluginLua::Load(void)
void cPluginLua::Unload(void)
{
- ClearTabs();
+ ClearWebTabs();
super::Unload();
Close();
}
@@ -216,12 +194,12 @@ void cPluginLua::Unload(void)
void cPluginLua::OnDisable(void)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.HasFunction("OnDisable"))
+ cOperation op(*this);
+ if (!op().HasFunction("OnDisable"))
{
return;
}
- m_LuaState.Call("OnDisable");
+ op().Call("OnDisable");
}
@@ -230,16 +208,7 @@ void cPluginLua::OnDisable(void)
void cPluginLua::Tick(float a_Dt)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return;
- }
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TICK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), a_Dt);
- }
+ CallSimpleHooks(cPluginManager::HOOK_TICK, a_Dt);
}
@@ -248,22 +217,7 @@ void cPluginLua::Tick(float a_Dt)
bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_SPREAD];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_BLOCK_SPREAD, &a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source);
}
@@ -272,22 +226,7 @@ bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int
bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_TO_PICKUPS];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_BLOCK_TO_PICKUPS, &a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups);
}
@@ -296,22 +235,7 @@ bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_Bl
bool cPluginLua::OnBrewingCompleted(cWorld & a_World, cBrewingstandEntity & a_Brewingstand)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BREWING_COMPLETED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Brewingstand, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_BREWING_COMPLETED, &a_World, &a_Brewingstand);
}
@@ -320,22 +244,7 @@ bool cPluginLua::OnBrewingCompleted(cWorld & a_World, cBrewingstandEntity & a_Br
bool cPluginLua::OnBrewingCompleting(cWorld & a_World, cBrewingstandEntity & a_Brewingstand)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BREWING_COMPLETING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Brewingstand, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_BREWING_COMPLETING, &a_World, &a_Brewingstand);
}
@@ -344,16 +253,16 @@ bool cPluginLua::OnBrewingCompleting(cWorld & a_World, cBrewingstandEntity & a_B
bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
return false;
}
bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHAT];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ auto & hooks = m_HookMap[cPluginManager::HOOK_CHAT];
+ for (auto & hook: hooks)
{
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_Message, cLuaState::Return, res, a_Message);
+ hook->Call(&a_Player, a_Message, cLuaState::Return, res, a_Message);
if (res)
{
return true;
@@ -368,22 +277,7 @@ bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_AVAILABLE];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_CHUNK_AVAILABLE, &a_World, a_ChunkX, a_ChunkZ);
}
@@ -392,22 +286,7 @@ bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_CHUNK_GENERATED, &a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc);
}
@@ -416,22 +295,7 @@ bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ,
bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_CHUNK_GENERATING, &a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc);
}
@@ -440,22 +304,7 @@ bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ,
bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_CHUNK_UNLOADED, &a_World, a_ChunkX, a_ChunkZ);
}
@@ -464,22 +313,7 @@ bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_CHUNK_UNLOADING, &a_World, a_ChunkX, a_ChunkZ);
}
@@ -488,22 +322,7 @@ bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_COLLECTING_PICKUP];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, &a_Pickup, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_COLLECTING_PICKUP, &a_Player, &a_Pickup);
}
@@ -512,22 +331,7 @@ bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup)
bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CRAFTING_NO_RECIPE];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, &a_Grid, &a_Recipe, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_CRAFTING_NO_RECIPE, &a_Player, &a_Grid, &a_Recipe);
}
@@ -536,22 +340,7 @@ bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid,
bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Client, a_Reason, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_DISCONNECT, &a_Client, a_Reason);
}
@@ -560,22 +349,7 @@ bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason
bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_ADD_EFFECT];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Entity, a_EffectType, a_EffectDurationTicks, a_EffectIntensity, a_DistanceModifier, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_ENTITY_ADD_EFFECT, &a_Entity, a_EffectType, a_EffectDurationTicks, a_EffectIntensity, a_DistanceModifier);
}
@@ -584,22 +358,7 @@ bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_E
bool cPluginLua::OnEntityChangingWorld(cEntity & a_Entity, cWorld & a_World)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_CHANGING_WORLD];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Entity, &a_World, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_ENTITY_CHANGING_WORLD, &a_Entity, &a_World);
}
@@ -608,22 +367,7 @@ bool cPluginLua::OnEntityChangingWorld(cEntity & a_Entity, cWorld & a_World)
bool cPluginLua::OnEntityChangedWorld(cEntity & a_Entity, cWorld & a_World)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_CHANGED_WORLD];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Entity, &a_World, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_ENTITY_CHANGED_WORLD, &a_Entity, &a_World);
}
@@ -632,16 +376,16 @@ bool cPluginLua::OnEntityChangedWorld(cEntity & a_Entity, cWorld & a_World)
bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
return false;
}
bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ auto & hooks = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND];
+ for (auto & hook: hooks)
{
- m_LuaState.Call(static_cast<int>(**itr), a_Player, a_Split, a_EntireCommand, cLuaState::Return, res, a_Result);
+ hook->Call(a_Player, a_Split, a_EntireCommand, cLuaState::Return, res, a_Result);
if (res)
{
return true;
@@ -656,26 +400,26 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp
bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
return false;
}
bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ auto & hooks = m_HookMap[cPluginManager::HOOK_EXPLODED];
+ for (auto & hook: hooks)
{
switch (a_Source)
{
- case esBed: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<Vector3i *> (a_SourceData), cLuaState::Return, res); break;
- case esEnderCrystal: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cEntity *> (a_SourceData), cLuaState::Return, res); break;
- case esGhastFireball: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cGhastFireballEntity *>(a_SourceData), cLuaState::Return, res); break;
- case esMonster: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cMonster *> (a_SourceData), cLuaState::Return, res); break;
- case esOther: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break;
- case esPlugin: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break;
- case esPrimedTNT: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cTNTEntity *> (a_SourceData), cLuaState::Return, res); break;
- case esWitherBirth: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cMonster *> (a_SourceData), cLuaState::Return, res); break;
- case esWitherSkull: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cWitherSkullEntity *> (a_SourceData), cLuaState::Return, res); break;
+ case esBed: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<Vector3i *> (a_SourceData), cLuaState::Return, res); break;
+ case esEnderCrystal: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cEntity *> (a_SourceData), cLuaState::Return, res); break;
+ case esGhastFireball: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cGhastFireballEntity *>(a_SourceData), cLuaState::Return, res); break;
+ case esMonster: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cMonster *> (a_SourceData), cLuaState::Return, res); break;
+ case esOther: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break;
+ case esPlugin: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break;
+ case esPrimedTNT: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cTNTEntity *> (a_SourceData), cLuaState::Return, res); break;
+ case esWitherBirth: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cMonster *> (a_SourceData), cLuaState::Return, res); break;
+ case esWitherSkull: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cWitherSkullEntity *> (a_SourceData), cLuaState::Return, res); break;
case esMax:
{
ASSERT(!"Invalid explosion source");
@@ -696,26 +440,26 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can
bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
return false;
}
bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ auto & hooks = m_HookMap[cPluginManager::HOOK_EXPLODING];
+ for (auto & hook: hooks)
{
switch (a_Source)
{
- case esBed: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<Vector3i *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esEnderCrystal: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cEntity *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esGhastFireball: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cGhastFireballEntity *>(a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esMonster: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cMonster *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esOther: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esPlugin: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esPrimedTNT: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cTNTEntity *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esWitherBirth: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cMonster *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esWitherSkull: m_LuaState.Call(static_cast<int>(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cWitherSkullEntity *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esBed: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<Vector3i *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esEnderCrystal: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cEntity *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esGhastFireball: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cGhastFireballEntity *>(a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esMonster: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cMonster *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esOther: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esPlugin: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esPrimedTNT: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cTNTEntity *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esWitherBirth: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cMonster *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esWitherSkull: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast<cWitherSkullEntity *> (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esMax:
{
ASSERT(!"Invalid explosion source");
@@ -736,22 +480,7 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool &
bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Username)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HANDSHAKE];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Client, a_Username, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_HANDSHAKE, &a_Client, a_Username);
}
@@ -760,22 +489,7 @@ bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Usernam
bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PULLING_ITEM];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Hopper, a_DstSlotNum, &a_SrcEntity, a_SrcSlotNum, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_HOPPER_PULLING_ITEM, &a_World, &a_Hopper, a_DstSlotNum, &a_SrcEntity, a_SrcSlotNum);
}
@@ -784,22 +498,7 @@ bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper,
bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PUSHING_ITEM];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Hopper, a_SrcSlotNum, &a_DstEntity, a_DstSlotNum, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_HOPPER_PUSHING_ITEM, &a_World, &a_Hopper, a_SrcSlotNum, &a_DstEntity, a_DstSlotNum);
}
@@ -808,16 +507,16 @@ bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper,
bool cPluginLua::OnKilled(cEntity & a_Victim, TakeDamageInfo & a_TDI, AString & a_DeathMessage)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
return false;
}
bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_KILLED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ auto & hooks = m_HookMap[cPluginManager::HOOK_KILLED];
+ for (auto & hook: hooks)
{
- m_LuaState.Call(static_cast<int>(**itr), &a_Victim, &a_TDI, a_DeathMessage, cLuaState::Return, res, a_DeathMessage);
+ hook->Call(&a_Victim, &a_TDI, a_DeathMessage, cLuaState::Return, res, a_DeathMessage);
if (res)
{
return true;
@@ -832,22 +531,7 @@ bool cPluginLua::OnKilled(cEntity & a_Victim, TakeDamageInfo & a_TDI, AString &
bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_KILLING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Victim, a_Killer, &a_TDI, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_KILLING, &a_Victim, a_Killer, &a_TDI);
}
@@ -856,22 +540,7 @@ bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInf
bool cPluginLua::OnLogin(cClientHandle & a_Client, UInt32 a_ProtocolVersion, const AString & a_Username)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_LOGIN];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Client, a_ProtocolVersion, a_Username, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_LOGIN, &a_Client, a_ProtocolVersion, a_Username);
}
@@ -880,22 +549,7 @@ bool cPluginLua::OnLogin(cClientHandle & a_Client, UInt32 a_ProtocolVersion, con
bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_ANIMATION];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_Animation, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_ANIMATION, &a_Player, a_Animation);
}
@@ -904,22 +558,7 @@ bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation)
bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BREAKING_BLOCK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_BREAKING_BLOCK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta);
}
@@ -928,22 +567,7 @@ bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_B
bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BROKEN_BLOCK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_BROKEN_BLOCK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta);
}
@@ -952,22 +576,7 @@ bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_Blo
bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_DESTROYED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_DESTROYED, &a_Player);
}
@@ -976,22 +585,7 @@ bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player)
bool cPluginLua::OnPlayerEating(cPlayer & a_Player)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_EATING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_EATING, &a_Player);
}
@@ -1000,22 +594,7 @@ bool cPluginLua::OnPlayerEating(cPlayer & a_Player)
bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FOOD_LEVEL_CHANGE];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_NewFoodLevel, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_FOOD_LEVEL_CHANGE, &a_Player, a_NewFoodLevel);
}
@@ -1024,22 +603,7 @@ bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel)
bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_Reward, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_FISHED, &a_Player, a_Reward);
}
@@ -1048,22 +612,7 @@ bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, &a_Reward, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_FISHING, &a_Player, &a_Reward);
}
@@ -1072,22 +621,7 @@ bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward)
bool cPluginLua::OnPlayerJoined(cPlayer & a_Player)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_JOINED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_JOINED, &a_Player);
}
@@ -1096,22 +630,7 @@ bool cPluginLua::OnPlayerJoined(cPlayer & a_Player)
bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_LEFT_CLICK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_LEFT_CLICK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status);
}
@@ -1120,22 +639,7 @@ bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_Block
bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_MOVING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_OldPosition, a_NewPosition, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_MOVING, &a_Player, a_OldPosition, a_NewPosition);
}
@@ -1144,22 +648,7 @@ bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPositi
bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_TELEPORT];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Entity, a_OldPosition, a_NewPosition, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_ENTITY_TELEPORT, &a_Entity, a_OldPosition, a_NewPosition);
}
@@ -1168,27 +657,11 @@ bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosi
bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player,
- a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(),
- a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta,
- cLuaState::Return,
- res
- );
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_PLACED_BLOCK,
+ &a_Player,
+ a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(),
+ a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta
+ );
}
@@ -1197,27 +670,11 @@ bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_Blo
bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player,
- a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(),
- a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta,
- cLuaState::Return,
- res
- );
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_PLACING_BLOCK,
+ &a_Player,
+ a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(),
+ a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta
+ );
}
@@ -1226,22 +683,7 @@ bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_Bl
bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_RIGHT_CLICK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
}
@@ -1250,22 +692,7 @@ bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_Bloc
bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, &a_Entity, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY, &a_Player, &a_Entity);
}
@@ -1274,22 +701,7 @@ bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Ent
bool cPluginLua::OnPlayerShooting(cPlayer & a_Player)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SHOOTING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_SHOOTING, &a_Player);
}
@@ -1298,22 +710,7 @@ bool cPluginLua::OnPlayerShooting(cPlayer & a_Player)
bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SPAWNED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_SPAWNED, &a_Player);
}
@@ -1322,22 +719,7 @@ bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player)
bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_TOSSING_ITEM];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_TOSSING_ITEM, &a_Player);
}
@@ -1346,22 +728,7 @@ bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player)
bool cPluginLua::OnPlayerUsedBlock(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)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_BLOCK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_USED_BLOCK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta);
}
@@ -1370,22 +737,7 @@ bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_Block
bool cPluginLua::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)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_ITEM];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_USED_ITEM, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
}
@@ -1394,22 +746,7 @@ bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY
bool cPluginLua::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)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_BLOCK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_USING_BLOCK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta);
}
@@ -1418,22 +755,7 @@ bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_Bloc
bool cPluginLua::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)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_ITEM];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLAYER_USING_ITEM, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
}
@@ -1442,22 +764,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)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Client, a_Channel, a_Message, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PLUGIN_MESSAGE, &a_Client, a_Channel, a_Message);
}
@@ -1466,17 +773,17 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha
bool cPluginLua::OnPluginsLoaded(void)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
return false;
}
bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ auto & hooks = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED];
+ for (auto & hook: hooks)
{
bool ret = false;
- m_LuaState.Call(static_cast<int>(**itr), cLuaState::Return, ret);
+ hook->Call(cLuaState::Return, ret);
res = res || ret;
}
return res;
@@ -1488,22 +795,7 @@ bool cPluginLua::OnPluginsLoaded(void)
bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_POST_CRAFTING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, &a_Grid, &a_Recipe, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_POST_CRAFTING, &a_Player, &a_Grid, &a_Recipe);
}
@@ -1512,22 +804,7 @@ bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCra
bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PRE_CRAFTING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Player, &a_Grid, &a_Recipe, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PRE_CRAFTING, &a_Player, &a_Grid, &a_Recipe);
}
@@ -1536,22 +813,7 @@ bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraf
bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_BLOCK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Projectile, a_BlockX, a_BlockY, a_BlockZ, a_Face, a_BlockHitPos, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PROJECTILE_HIT_BLOCK, &a_Projectile, a_BlockX, a_BlockY, a_BlockZ, a_Face, a_BlockHitPos);
}
@@ -1560,22 +822,7 @@ bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_Bl
bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_ENTITY];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Projectile, &a_HitEntity, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_PROJECTILE_HIT_ENTITY, &a_Projectile, &a_HitEntity);
}
@@ -1584,16 +831,16 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity
bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
return false;
}
bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ auto & hooks = m_HookMap[cPluginManager::HOOK_SERVER_PING];
+ for (auto & hook: hooks)
{
- m_LuaState.Call(static_cast<int>(**itr), &a_ClientHandle, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon);
+ hook->Call(&a_ClientHandle, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon);
if (res)
{
return true;
@@ -1608,22 +855,7 @@ bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_Server
bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_ENTITY];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Entity, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_SPAWNED_ENTITY, &a_World, &a_Entity);
}
@@ -1632,22 +864,7 @@ bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_MONSTER];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Monster, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_SPAWNED_MONSTER, &a_World, &a_Monster);
}
@@ -1656,22 +873,7 @@ bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster)
bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_ENTITY];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Entity, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_SPAWNING_ENTITY, &a_World, &a_Entity);
}
@@ -1680,22 +882,7 @@ bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity)
bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_MONSTER];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Monster, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_SPAWNING_MONSTER, &a_World, &a_Monster);
}
@@ -1704,22 +891,7 @@ bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster)
bool cPluginLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TAKE_DAMAGE];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_Receiver, &a_TDI, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_TAKE_DAMAGE, &a_Receiver, &a_TDI);
}
@@ -1733,22 +905,7 @@ bool cPluginLua::OnUpdatedSign(
cPlayer * a_Player
)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATED_SIGN];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_UPDATED_SIGN, &a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player);
}
@@ -1762,16 +919,16 @@ bool cPluginLua::OnUpdatingSign(
cPlayer * a_Player
)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
return false;
}
bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ auto & hooks = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN];
+ for (auto & hook: hooks)
{
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res, a_Line1, a_Line2, a_Line3, a_Line4);
+ hook->Call(&a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res, a_Line1, a_Line2, a_Line3, a_Line4);
if (res)
{
return true;
@@ -1786,22 +943,7 @@ bool cPluginLua::OnUpdatingSign(
bool cPluginLua::OnWeatherChanged(cWorld & a_World)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, cLuaState::Return, res);
- if (res)
- {
- return true;
- }
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_WEATHER_CHANGED, &a_World);
}
@@ -1810,16 +952,16 @@ bool cPluginLua::OnWeatherChanged(cWorld & a_World)
bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
+ cOperation op(*this);
+ if (!op().IsValid())
{
return false;
}
bool res = false;
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ auto & hooks = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING];
+ for (auto & hook: hooks)
{
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_NewWeather, cLuaState::Return, res, a_NewWeather);
+ hook->Call(&a_World, a_NewWeather, cLuaState::Return, res, a_NewWeather);
if (res)
{
return true;
@@ -1834,17 +976,7 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
bool cPluginLua::OnWorldStarted(cWorld & a_World)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_STARTED];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World);
- }
- return false;
+ return CallSimpleHooks(cPluginManager::HOOK_WORLD_STARTED, &a_World);
}
@@ -1853,102 +985,7 @@ bool cPluginLua::OnWorldStarted(cWorld & a_World)
bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
{
- cCSLock Lock(m_CriticalSection);
- if (!m_LuaState.IsValid())
- {
- return false;
- }
- cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK];
- for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
- {
- m_LuaState.Call(static_cast<int>(**itr), &a_World, a_Dt, a_LastTickDurationMSec);
- }
- return false;
-}
-
-
-
-
-
-bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand)
-{
- ASSERT(!a_Split.empty());
- CommandMap::iterator cmd = m_Commands.find(a_Split[0]);
- if (cmd == m_Commands.end())
- {
- LOGWARNING("Command handler is registered in cPluginManager but not in cPlugin, wtf? Command \"%s\".", a_Split[0].c_str());
- return false;
- }
-
- cCSLock Lock(m_CriticalSection);
- bool res = false;
- m_LuaState.Call(cmd->second, a_Split, &a_Player, a_FullCommand, cLuaState::Return, res);
- return res;
-}
-
-
-
-
-
-bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand)
-{
- ASSERT(!a_Split.empty());
- CommandMap::iterator cmd = m_ConsoleCommands.find(a_Split[0]);
- if (cmd == m_ConsoleCommands.end())
- {
- LOGWARNING("Console command handler is registered in cPluginManager but not in cPlugin, wtf? Console command \"%s\", plugin \"%s\".",
- a_Split[0].c_str(), GetName().c_str()
- );
- return false;
- }
-
- cCSLock Lock(m_CriticalSection);
- bool res = false;
- AString str;
- m_LuaState.Call(cmd->second, a_Split, a_FullCommand, cLuaState::Return, res, str);
- if (res && !str.empty())
- {
- a_Output.Out(str);
- }
- return res;
-}
-
-
-
-
-
-void cPluginLua::ClearCommands(void)
-{
- cCSLock Lock(m_CriticalSection);
-
- // Unreference the bound functions so that Lua can GC them
- if (m_LuaState != nullptr)
- {
- for (CommandMap::iterator itr = m_Commands.begin(), end = m_Commands.end(); itr != end; ++itr)
- {
- luaL_unref(m_LuaState, LUA_REGISTRYINDEX, itr->second);
- }
- }
- m_Commands.clear();
-}
-
-
-
-
-
-void cPluginLua::ClearConsoleCommands(void)
-{
- cCSLock Lock(m_CriticalSection);
-
- // Unreference the bound functions so that Lua can GC them
- if (m_LuaState != nullptr)
- {
- for (CommandMap::iterator itr = m_ConsoleCommands.begin(), end = m_ConsoleCommands.end(); itr != end; ++itr)
- {
- luaL_unref(m_LuaState, LUA_REGISTRYINDEX, itr->second);
- }
- }
- m_ConsoleCommands.clear();
+ return CallSimpleHooks(cPluginManager::HOOK_WORLD_TICK, &a_World, a_Dt, a_LastTickDurationMSec);
}
@@ -2059,22 +1096,9 @@ const char * cPluginLua::GetHookFnName(int a_HookType)
-bool cPluginLua::AddHookRef(int a_HookType, int a_FnRefIdx)
+bool cPluginLua::AddHookCallback(int a_HookType, cLuaState::cCallbackPtr && a_Callback)
{
- ASSERT(m_CriticalSection.IsLockedByCurrentThread()); // It probably has to be, how else would we have a LuaState?
-
- // Check if the function reference is valid:
- cLuaState::cRef * Ref = new cLuaState::cRef(m_LuaState, a_FnRefIdx);
- if ((Ref == nullptr) || !Ref->IsValid())
- {
- LOGWARNING("Plugin %s tried to add a hook %d with bad handler function.", GetName().c_str(), a_HookType);
- m_LuaState.LogStackTrace();
- delete Ref;
- Ref = nullptr;
- return false;
- }
-
- m_HookMap[a_HookType].push_back(Ref);
+ m_HookMap[a_HookType].push_back(std::move(a_Callback));
return true;
}
@@ -2089,10 +1113,10 @@ int cPluginLua::CallFunctionFromForeignState(
int a_ParamEnd
)
{
- cCSLock Lock(m_CriticalSection);
+ cOperation op(*this);
// Call the function:
- int NumReturns = m_LuaState.CallFunctionWithForeignParams(a_FunctionName, a_ForeignState, a_ParamStart, a_ParamEnd);
+ int NumReturns = op().CallFunctionWithForeignParams(a_FunctionName, a_ForeignState, a_ParamStart, a_ParamEnd);
if (NumReturns < 0)
{
// The call has failed, an error has already been output to the log, so just silently bail out with the same error
@@ -2116,133 +1140,13 @@ int cPluginLua::CallFunctionFromForeignState(
-void cPluginLua::AddResettable(cPluginLua::cResettablePtr a_Resettable)
-{
- cCSLock Lock(m_CriticalSection);
- m_Resettables.push_back(a_Resettable);
-}
-
-
-
-
-
-AString cPluginLua::HandleWebRequest(const HTTPRequest & a_Request)
-{
- // Find the tab to use for the request:
- auto TabName = GetTabNameForRequest(a_Request);
- AString SafeTabTitle = TabName.second;
- if (SafeTabTitle.empty())
- {
- return "";
- }
- auto Tab = GetTabBySafeTitle(SafeTabTitle);
- if (Tab == nullptr)
- {
- return "";
- }
-
- // Get the page content from the plugin:
- cCSLock Lock(m_CriticalSection);
- AString Contents = Printf("WARNING: WebPlugin tab '%s' did not return a string!", Tab->m_Title.c_str());
- if (!m_LuaState.Call(Tab->m_UserData, &a_Request, cLuaState::Return, Contents))
- {
- return "Lua encountered error while processing the page request";
- }
- return Contents;
-}
-
-
-
-
-
-bool cPluginLua::AddWebTab(const AString & a_Title, lua_State * a_LuaState, int a_FunctionReference)
+void cPluginLua::ClearWebTabs(void)
{
- cCSLock Lock(m_CriticalSection);
- if (a_LuaState != m_LuaState)
+ auto webAdmin = cRoot::Get()->GetWebAdmin();
+ if (webAdmin != nullptr) // can be nullptr when shutting down the server
{
- LOGERROR("Only allowed to add a tab to a WebPlugin of your own Plugin!");
- return false;
+ webAdmin->RemoveAllPluginWebTabs(m_Name);
}
- AddNewWebTab(a_Title, a_FunctionReference);
- return true;
-}
-
-
-
-
-
-void cPluginLua::BindCommand(const AString & a_Command, int a_FnRef)
-{
- ASSERT(m_Commands.find(a_Command) == m_Commands.end());
- m_Commands[a_Command] = a_FnRef;
-}
-
-
-
-
-
-void cPluginLua::BindConsoleCommand(const AString & a_Command, int a_FnRef)
-{
- ASSERT(m_ConsoleCommands.find(a_Command) == m_ConsoleCommands.end());
- m_ConsoleCommands[a_Command] = a_FnRef;
-}
-
-
-
-
-
-void cPluginLua::Unreference(int a_LuaRef)
-{
- cCSLock Lock(m_CriticalSection);
- luaL_unref(m_LuaState, LUA_REGISTRYINDEX, a_LuaRef);
-}
-
-
-
-
-
-bool cPluginLua::CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPlayer & a_Player, bool a_CanRefuse)
-{
- ASSERT(a_FnRef != LUA_REFNIL);
-
- cCSLock Lock(m_CriticalSection);
- bool res = false;
- m_LuaState.Call(a_FnRef, &a_Window, &a_Player, a_CanRefuse, cLuaState::Return, res);
- return res;
-}
-
-
-
-
-
-void cPluginLua::CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int a_SlotNum)
-{
- ASSERT(a_FnRef != LUA_REFNIL);
-
- cCSLock Lock(m_CriticalSection);
- m_LuaState.Call(a_FnRef, &a_Window, a_SlotNum);
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cPluginLua::cResettable:
-
-cPluginLua::cResettable::cResettable(cPluginLua & a_Plugin):
- m_Plugin(&a_Plugin)
-{
-}
-
-
-
-
-
-void cPluginLua::cResettable::Reset(void)
-{
- cCSLock Lock(m_CSPlugin);
- m_Plugin = nullptr;
}
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index db6612671..dc3c91880 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -10,7 +10,6 @@
#pragma once
#include "Plugin.h"
-#include "WebPlugin.h"
#include "LuaState.h"
// Names for the global variables through which the plugin is identified in its LuaState
@@ -29,8 +28,7 @@ class cWindow;
// tolua_begin
class cPluginLua :
- public cPlugin,
- public cWebPlugin
+ public cPlugin
{
typedef cPlugin super;
@@ -49,7 +47,7 @@ public:
public:
cOperation(cPluginLua & a_Plugin) :
m_Plugin(a_Plugin),
- m_Lock(a_Plugin.m_CriticalSection)
+ m_Lock(a_Plugin.m_LuaState)
{
}
@@ -58,42 +56,12 @@ public:
protected:
cPluginLua & m_Plugin;
- /** RAII lock for m_Plugin.m_CriticalSection */
- cCSLock m_Lock;
+ /** RAII lock for the Lua state. */
+ cLuaState::cLock m_Lock;
} ;
- /** A base class that represents something related to a plugin
- The plugin can reset this class so that the instance can continue to exist but will not engage the (possibly non-existent) plugin anymore.
- This is used for scheduled tasks etc., so that they can be queued and reset when the plugin is terminated, without removing them from the queue. */
- class cResettable
- {
- public:
- /** Creates a new instance bound to the specified plugin. */
- cResettable(cPluginLua & a_Plugin);
-
- // Force a virtual destructor in descendants:
- virtual ~cResettable() {}
-
- /** Resets the plugin instance stored within.
- The instance will continue to exist, but should not call into the plugin anymore. */
- virtual void Reset(void);
-
- protected:
- /** The plugin that this instance references.
- If nullptr, the plugin has already unloaded and the instance should bail out any processing.
- Protected against multithreaded access by m_CSPlugin. */
- cPluginLua * m_Plugin;
-
- /** The mutex protecting m_Plugin against multithreaded access. */
- cCriticalSection m_CSPlugin;
- };
-
- typedef SharedPtr<cResettable> cResettablePtr;
- typedef std::vector<cResettablePtr> cResettablePtrs;
-
-
cPluginLua(const AString & a_PluginDirectory);
~cPluginLua();
@@ -170,52 +138,15 @@ public:
virtual bool OnWorldStarted (cWorld & a_World) override;
virtual bool OnWorldTick (cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec) override;
- virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand) override;
-
- virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand) override;
-
- virtual void ClearCommands(void) override;
-
- virtual void ClearConsoleCommands(void) override;
-
/** Returns true if the plugin contains the function for the specified hook type, using the old-style registration (#121) */
bool CanAddOldStyleHook(int a_HookType);
- // cWebPlugin overrides
- virtual const AString GetWebTitle(void) const override {return GetName(); }
- virtual AString HandleWebRequest(const HTTPRequest & a_Request) override;
-
- /** Adds a new web tab to webadmin.
- Displaying the tab calls the referenced function. */
- bool AddWebTab(const AString & a_Title, lua_State * a_LuaState, int a_FunctionReference); // Exported in ManualBindings.cpp
-
- /** Binds the command to call the function specified by a Lua function reference. Simply adds to CommandMap. */
- void BindCommand(const AString & a_Command, int a_FnRef);
-
- /** Binds the console command to call the function specified by a Lua function reference. Simply adds to CommandMap. */
- void BindConsoleCommand(const AString & a_Command, int a_FnRef);
-
- cLuaState & GetLuaState(void) { return m_LuaState; }
-
- cCriticalSection & GetCriticalSection(void) { return m_CriticalSection; }
-
- /** Removes a previously referenced object (luaL_unref()) */
- void Unreference(int a_LuaRef);
-
- /** Calls the plugin-specified "cLuaWindow closing" callback. Returns true only if the callback returned true */
- bool CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPlayer & a_Player, bool a_CanRefuse);
-
- /** Calls the plugin-specified "cLuaWindow slot changed" callback. */
- void CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int a_SlotNum);
-
/** Returns the name of Lua function that should handle the specified hook type in the older (#121) API */
static const char * GetHookFnName(int a_HookType);
- /** Adds a Lua function to be called for the specified hook.
- The function has to be on the Lua stack at the specified index a_FnRefIdx
- Returns true if the hook was added successfully.
- */
- bool AddHookRef(int a_HookType, int a_FnRefIdx);
+ /** Adds a Lua callback to be called for the specified hook.
+ Returns true if the hook was added successfully. */
+ bool AddHookCallback(int a_HookType, cLuaState::cCallbackPtr && a_Callback);
/** Calls a function in this plugin's LuaState with parameters copied over from a_ForeignState.
The values that the function returns are placed onto a_ForeignState.
@@ -231,45 +162,50 @@ public:
template <typename FnT, typename... Args>
bool Call(FnT a_Fn, Args && ... a_Args)
{
- cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn, a_Args...);
+ return cOperation(*this)().Call(a_Fn, a_Args...);
}
- /** Adds the specified cResettable instance to m_Resettables, so that it is notified when the plugin is being closed. */
- void AddResettable(cResettablePtr a_Resettable);
-
protected:
- /** Maps command name into Lua function reference */
- typedef std::map<AString, int> CommandMap;
-
/** Provides an array of Lua function references */
- typedef std::vector<cLuaState::cRef *> cLuaRefs;
+ typedef std::vector<cLuaState::cCallbackPtr> cLuaCallbacks;
/** Maps hook types into arrays of Lua function references to call for each hook type */
- typedef std::map<int, cLuaRefs> cHookMap;
-
+ typedef std::map<int, cLuaCallbacks> cHookMap;
- /** The mutex protecting m_LuaState and each of the m_Resettables[] against multithreaded use. */
- cCriticalSection m_CriticalSection;
/** The plugin's Lua state. */
cLuaState m_LuaState;
- /** Objects that need notification when the plugin is about to be unloaded. */
- cResettablePtrs m_Resettables;
-
- /** In-game commands that the plugin has registered. */
- CommandMap m_Commands;
-
- /** Console commands that the plugin has registered. */
- CommandMap m_ConsoleCommands;
-
/** Hooks that the plugin has registered. */
cHookMap m_HookMap;
/** Releases all Lua references, notifies and removes all m_Resettables[] and closes the m_LuaState. */
void Close(void);
+
+ /** Removes all WebTabs currently registered for this plugin from the WebAdmin. */
+ void ClearWebTabs(void);
+
+ /** Calls a hook that has the simple format - single bool return value specifying whether the chain should continue.
+ The advanced hook types that need more processing implement a similar loop manually instead.
+ Returns true if any of hook calls wants to abort the hook (returned true), false if all hook calls returned false. */
+ template <typename... Args>
+ bool CallSimpleHooks(int a_HookType, Args && ... a_Args)
+ {
+ cOperation op(*this);
+ auto & hooks = m_HookMap[a_HookType];
+ bool res = false;
+ for (auto & hook: hooks)
+ {
+ hook->Call(std::forward<Args>(a_Args)..., cLuaState::Return, res);
+ if (res)
+ {
+ // Hook wants to terminate the chain processing
+ return true;
+ }
+ }
+ return false;
+ }
} ; // tolua_export
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index 5b3ef7803..19d2e8b4d 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -1569,9 +1569,9 @@ cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer & a_Player,
return crNoPermission;
}
- ASSERT(cmd->second.m_Plugin != nullptr);
+ ASSERT(cmd->second.m_Handler != nullptr);
- if (!cmd->second.m_Plugin->HandleCommand(Split, a_Player, a_Command))
+ if (!cmd->second.m_Handler->ExecuteCommand(Split, &a_Player, a_Command, nullptr))
{
return crError;
}
@@ -1654,11 +1654,6 @@ void cPluginManager::RemoveHooks(cPlugin * a_Plugin)
void cPluginManager::RemovePluginCommands(cPlugin * a_Plugin)
{
- if (a_Plugin != nullptr)
- {
- a_Plugin->ClearCommands();
- }
-
for (CommandMap::iterator itr = m_Commands.begin(); itr != m_Commands.end();)
{
if (itr->second.m_Plugin == a_Plugin)
@@ -1694,7 +1689,13 @@ bool cPluginManager::IsPluginLoaded(const AString & a_PluginName)
-bool cPluginManager::BindCommand(const AString & a_Command, cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString)
+bool cPluginManager::BindCommand(
+ const AString & a_Command,
+ cPlugin * a_Plugin,
+ cCommandHandlerPtr a_Handler,
+ const AString & a_Permission,
+ const AString & a_HelpString
+)
{
CommandMap::iterator cmd = m_Commands.find(a_Command);
if (cmd != m_Commands.end())
@@ -1703,9 +1704,11 @@ bool cPluginManager::BindCommand(const AString & a_Command, cPlugin * a_Plugin,
return false;
}
- m_Commands[a_Command].m_Plugin = a_Plugin;
- m_Commands[a_Command].m_Permission = a_Permission;
- m_Commands[a_Command].m_HelpString = a_HelpString;
+ auto & reg = m_Commands[a_Command];
+ reg.m_Plugin = a_Plugin;
+ reg.m_Handler = a_Handler;
+ reg.m_Permission = a_Permission;
+ reg.m_HelpString = a_HelpString;
return true;
}
@@ -1768,11 +1771,6 @@ cPluginManager::CommandResult cPluginManager::ForceExecuteCommand(cPlayer & a_Pl
void cPluginManager::RemovePluginConsoleCommands(cPlugin * a_Plugin)
{
- if (a_Plugin != nullptr)
- {
- a_Plugin->ClearConsoleCommands();
- }
-
for (CommandMap::iterator itr = m_ConsoleCommands.begin(); itr != m_ConsoleCommands.end();)
{
if (itr->second.m_Plugin == a_Plugin)
@@ -1792,7 +1790,12 @@ void cPluginManager::RemovePluginConsoleCommands(cPlugin * a_Plugin)
-bool cPluginManager::BindConsoleCommand(const AString & a_Command, cPlugin * a_Plugin, const AString & a_HelpString)
+bool cPluginManager::BindConsoleCommand(
+ const AString & a_Command,
+ cPlugin * a_Plugin,
+ cCommandHandlerPtr a_Handler,
+ const AString & a_HelpString
+)
{
CommandMap::iterator cmd = m_ConsoleCommands.find(a_Command);
if (cmd != m_ConsoleCommands.end())
@@ -1808,9 +1811,11 @@ bool cPluginManager::BindConsoleCommand(const AString & a_Command, cPlugin * a_P
return false;
}
- m_ConsoleCommands[a_Command].m_Plugin = a_Plugin;
- m_ConsoleCommands[a_Command].m_Permission = "";
- m_ConsoleCommands[a_Command].m_HelpString = a_HelpString;
+ auto & reg = m_ConsoleCommands[a_Command];
+ reg.m_Plugin = a_Plugin;
+ reg.m_Handler = a_Handler;
+ reg.m_Permission = "";
+ reg.m_HelpString = a_HelpString;
return true;
}
@@ -1873,7 +1878,7 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma
return (res == crExecuted);
}
- return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output, a_Command);
+ return cmd->second.m_Handler->ExecuteCommand(a_Split, nullptr, a_Command, &a_Output);
}
@@ -1965,6 +1970,23 @@ bool cPluginManager::ForEachPlugin(cPluginCallback & a_Callback)
+AString cPluginManager::GetPluginFolderName(const AString & a_PluginName)
+{
+ // TODO: Implement locking for plugins
+ for (auto & plugin: m_Plugins)
+ {
+ if (plugin->GetName() == a_PluginName)
+ {
+ return plugin->GetFolderName();
+ }
+ }
+ return AString();
+}
+
+
+
+
+
void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook)
{
if (a_Plugin == nullptr)
diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h
index f3f0b6d0b..0423d6af1 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -152,6 +152,7 @@ public:
HOOK_MAX = HOOK_NUM_HOOKS - 1,
} ; // tolua_export
+
/** Used as a callback for enumerating bound commands */
class cCommandEnumCallback
{
@@ -164,6 +165,30 @@ public:
virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) = 0;
} ;
+
+ /** Interface that must be provided by any class that implements a command handler, either in-game or console command. */
+ class cCommandHandler
+ {
+ public:
+ // Force a virtual destructor in descendants
+ virtual ~cCommandHandler() {}
+
+ /** Executes the specified in-game command.
+ a_Split is the command string, split at the spaces.
+ a_Player is the player executing the command, nullptr in case of the console.
+ a_Command is the entire command string.
+ a_Output is the sink into which the additional text returned by the command handler should be sent; only used for console commands. */
+ virtual bool ExecuteCommand(
+ const AStringVector & a_Split,
+ cPlayer * a_Player,
+ const AString & a_Command,
+ cCommandOutputCallback * a_Output = nullptr
+ ) = 0;
+ };
+
+ typedef SharedPtr<cCommandHandler> cCommandHandlerPtr;
+
+
/** The interface used for enumerating and extern-calling plugins */
typedef cItemCallback<cPlugin> cPluginCallback;
@@ -281,8 +306,16 @@ public:
/** Returns true if the specified plugin is loaded. */
bool IsPluginLoaded(const AString & a_PluginName); // tolua_export
- /** Binds a command to the specified plugin. Returns true if successful, false if command already bound. */
- bool BindCommand(const AString & a_Command, cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString); // Exported in ManualBindings.cpp, without the a_Plugin param
+ /** Binds a command to the specified handler.
+ Returns true if successful, false if command already bound.
+ Exported in ManualBindings.cpp. */
+ bool BindCommand(
+ const AString & a_Command,
+ cPlugin * a_Plugin,
+ cCommandHandlerPtr a_Handler,
+ const AString & a_Permission,
+ const AString & a_HelpString
+ );
/** Calls a_Callback for each bound command, returns true if all commands were enumerated */
bool ForEachCommand(cCommandEnumCallback & a_Callback); // Exported in ManualBindings.cpp
@@ -302,8 +335,15 @@ public:
/** Removes all console command bindings that the specified plugin has made */
void RemovePluginConsoleCommands(cPlugin * a_Plugin);
- /** Binds a console command to the specified plugin. Returns true if successful, false if command already bound. */
- bool BindConsoleCommand(const AString & a_Command, cPlugin * a_Plugin, const AString & a_HelpString); // Exported in ManualBindings.cpp, without the a_Plugin param
+ /** Binds a console command to the specified handler.
+ Returns true if successful, false if command already bound.
+ Exported in ManualBindings.cpp. */
+ bool BindConsoleCommand(
+ const AString & a_Command,
+ cPlugin * a_Plugin,
+ cCommandHandlerPtr a_Handler,
+ const AString & a_HelpString
+ );
/** Calls a_Callback for each bound console command, returns true if all commands were enumerated */
bool ForEachConsoleCommand(cCommandEnumCallback & a_Callback); // Exported in ManualBindings.cpp
@@ -332,6 +372,9 @@ public:
Returns true if all plugins have been reported, false if the callback has aborted the enumeration by returning true. */
bool ForEachPlugin(cPluginCallback & a_Callback);
+ /** Returns the name of the folder (cPlugin::GetFolderName()) from which the specified plugin was loaded. */
+ AString GetPluginFolderName(const AString & a_PluginName); // tolua_export
+
/** Returns the path where individual plugins' folders are expected.
The path doesn't end in a slash. */
static AString GetPluginsPath(void) { return FILE_IO_PREFIX + AString("Plugins"); } // tolua_export
@@ -345,6 +388,7 @@ private:
cPlugin * m_Plugin;
AString m_Permission; // Not used for console commands
AString m_HelpString;
+ cCommandHandlerPtr m_Handler;
} ;
typedef std::map<int, cPluginManager::PluginList> HookMap;
diff --git a/src/Bindings/WebPlugin.cpp b/src/Bindings/WebPlugin.cpp
deleted file mode 100644
index 1eca7de93..000000000
--- a/src/Bindings/WebPlugin.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "WebPlugin.h"
-#include "../WebAdmin.h"
-#include "../Root.h"
-
-
-
-
-
-cWebPlugin::cWebPlugin()
-{
- cWebAdmin * WebAdmin = cRoot::Get()->GetWebAdmin();
- if (WebAdmin != nullptr)
- {
- WebAdmin->AddPlugin(this);
- }
-}
-
-
-
-
-
-cWebPlugin::~cWebPlugin()
-{
- ASSERT(m_Tabs.empty()); // Has ClearTabs() been called?
-
- // Remove from WebAdmin:
- cWebAdmin * WebAdmin = cRoot::Get()->GetWebAdmin();
- if (WebAdmin != nullptr)
- {
- WebAdmin->RemovePlugin(this);
- }
-}
-
-
-
-
-
-cWebPlugin::cTabNames cWebPlugin::GetTabNames(void) const
-{
- std::list< std::pair<AString, AString>> NameList;
- for (auto itr = m_Tabs.cbegin(), end = m_Tabs.cend(); itr != end; ++itr)
- {
- NameList.push_back(std::make_pair((*itr)->m_Title, (*itr)->m_SafeTitle));
- }
- return NameList;
-}
-
-
-
-
-
-cWebPlugin::cTabPtr cWebPlugin::GetTabBySafeTitle(const AString & a_SafeTitle) const
-{
- cCSLock Lock(m_CSTabs);
- for (auto itr = m_Tabs.cbegin(), end = m_Tabs.cend(); itr != end; ++itr)
- {
- if ((*itr)->m_SafeTitle == a_SafeTitle)
- {
- return *itr;
- }
- }
- return nullptr;
-}
-
-
-
-
-
-std::pair<AString, AString> cWebPlugin::GetTabNameForRequest(const HTTPRequest & a_Request)
-{
- AStringVector Split = StringSplit(a_Request.Path, "/");
- if (Split.empty())
- {
- return std::make_pair(AString(), AString());
- }
-
- cCSLock Lock(m_CSTabs);
- cTabPtr Tab;
- if (Split.size() > 2) // If we got the tab name, show that page
- {
- for (auto itr = m_Tabs.cbegin(), end = m_Tabs.cend(); itr != end; ++itr)
- {
- if ((*itr)->m_SafeTitle.compare(Split[2]) == 0) // This is the one!
- {
- return std::make_pair((*itr)->m_Title, (*itr)->m_SafeTitle);
- }
- }
- // Tab name not found, display an "empty" page:
- return std::make_pair(AString(), AString());
- }
-
- // Show the first tab:
- if (!m_Tabs.empty())
- {
- return std::make_pair(m_Tabs.front()->m_SafeTitle, m_Tabs.front()->m_SafeTitle);
- }
-
- // No tabs at all:
- return std::make_pair(AString(), AString());
-}
-
-
-
-
-AString cWebPlugin::SafeString(const AString & a_String)
-{
- AString RetVal;
- auto len = a_String.size();
- RetVal.reserve(len);
- for (size_t i = 0; i < len; ++i)
- {
- char c = a_String[i];
- if (c == ' ')
- {
- c = '_';
- }
- RetVal.push_back(c);
- }
- return RetVal;
-}
-
-
-
-
-
-void cWebPlugin::AddNewWebTab(const AString & a_Title, int a_UserData)
-{
- auto Tab = std::make_shared<cTab>(a_Title, a_UserData);
- cCSLock Lock(m_CSTabs);
- m_Tabs.push_back(Tab);
-}
-
-
-
-
-
-void cWebPlugin::ClearTabs(void)
-{
- // Remove the webadmin tabs:
- cTabPtrs Tabs;
- {
- cCSLock Lock(m_CSTabs);
- std::swap(Tabs, m_Tabs);
- }
-}
-
-
-
-
diff --git a/src/Bindings/WebPlugin.h b/src/Bindings/WebPlugin.h
deleted file mode 100644
index 6dc8db801..000000000
--- a/src/Bindings/WebPlugin.h
+++ /dev/null
@@ -1,80 +0,0 @@
-
-#pragma once
-
-struct HTTPRequest;
-
-
-
-
-
-// tolua_begin
-class cWebPlugin
-{
-public:
- // tolua_end
-
- struct cTab
- {
- AString m_Title;
- AString m_SafeTitle;
- int m_UserData;
-
- cTab(const AString & a_Title, int a_UserData):
- m_Title(a_Title),
- m_SafeTitle(cWebPlugin::SafeString(a_Title)),
- m_UserData(a_UserData)
- {
- }
- };
-
- typedef SharedPtr<cTab> cTabPtr;
- typedef std::list<cTabPtr> cTabPtrs;
- typedef std::list<std::pair<AString, AString>> cTabNames;
-
-
- cWebPlugin();
-
- virtual ~cWebPlugin();
-
- // tolua_begin
-
- /** Returns the title of the plugin, as it should be presented in the webadmin's pages tree. */
- virtual const AString GetWebTitle(void) const = 0;
-
- /** Sanitizes the input string, replacing spaces with underscores. */
- static AString SafeString(const AString & a_String);
-
- // tolua_end
-
- virtual AString HandleWebRequest(const HTTPRequest & a_Request) = 0;
-
- /** Adds a new web tab with the specified contents. */
- void AddNewWebTab(const AString & a_Title, int a_UserData);
-
- /** Removes all the tabs. */
- void ClearTabs(void);
-
- /** Returns all the tabs that this plugin has registered. */
- const cTabPtrs & GetTabs(void) const { return m_Tabs; }
-
- /** Returns all of the tabs that this plugin has registered. */
- cTabNames GetTabNames(void) const; // Exported in ManualBindings.cpp
-
- /** Returns the tab that has the specified SafeTitle.
- Returns nullptr if no such tab. */
- cTabPtr GetTabBySafeTitle(const AString & a_SafeTitle) const;
-
- std::pair<AString, AString> GetTabNameForRequest(const HTTPRequest & a_Request);
-
-private:
- /** All tabs that this plugin has registered.
- Protected against multithreaded access by m_CSTabs. */
- cTabPtrs m_Tabs;
-
- /** Protects m_Tabs against multithreaded access. */
- mutable cCriticalSection m_CSTabs;
-}; // tolua_export
-
-
-
-
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 2f1e892dc..f6e9da45e 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -224,11 +224,11 @@ public:
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
const cWindow * GetWindow(void) const { return m_CurrentWindow; }
- /** Opens the specified window; closes the current one first using CloseWindow() */
- void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp
-
// tolua_begin
+ /** Opens the specified window; closes the current one first using CloseWindow() */
+ void OpenWindow(cWindow * a_Window);
+
/** Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true */
void CloseWindow(bool a_CanRefuse = true);
diff --git a/src/Server.cpp b/src/Server.cpp
index 5548e77d1..8405109de 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -607,18 +607,35 @@ void cServer::PrintHelp(const AStringVector & a_Split, cCommandOutputCallback &
void cServer::BindBuiltInConsoleCommands(void)
{
+ // Create an empty handler - the actual handling for the commands is performed before they are handed off to cPluginManager
+ class cEmptyHandler:
+ public cPluginManager::cCommandHandler
+ {
+ virtual bool ExecuteCommand(
+ const AStringVector & a_Split,
+ cPlayer * a_Player,
+ const AString & a_Command,
+ cCommandOutputCallback * a_Output = nullptr
+ ) override
+ {
+ return false;
+ }
+ };
+ auto handler = std::make_shared<cEmptyHandler>();
+
+ // Register internal commands:
cPluginManager * PlgMgr = cPluginManager::Get();
- PlgMgr->BindConsoleCommand("help", nullptr, "Shows the available commands");
- PlgMgr->BindConsoleCommand("reload", nullptr, "Reloads all plugins");
- PlgMgr->BindConsoleCommand("restart", nullptr, "Restarts the server cleanly");
- PlgMgr->BindConsoleCommand("stop", nullptr, "Stops the server cleanly");
- PlgMgr->BindConsoleCommand("chunkstats", nullptr, "Displays detailed chunk memory statistics");
- PlgMgr->BindConsoleCommand("load <pluginname>", nullptr, "Adds and enables the specified plugin");
- PlgMgr->BindConsoleCommand("unload <pluginname>", nullptr, "Disables the specified plugin");
- PlgMgr->BindConsoleCommand("destroyentities", nullptr, "Destroys all entities in all worlds");
+ PlgMgr->BindConsoleCommand("help", nullptr, handler, "Shows the available commands");
+ PlgMgr->BindConsoleCommand("reload", nullptr, handler, "Reloads all plugins");
+ PlgMgr->BindConsoleCommand("restart", nullptr, handler, "Restarts the server cleanly");
+ PlgMgr->BindConsoleCommand("stop", nullptr, handler, "Stops the server cleanly");
+ PlgMgr->BindConsoleCommand("chunkstats", nullptr, handler, "Displays detailed chunk memory statistics");
+ PlgMgr->BindConsoleCommand("load", nullptr, handler, "Adds and enables the specified plugin");
+ PlgMgr->BindConsoleCommand("unload", nullptr, handler, "Disables the specified plugin");
+ PlgMgr->BindConsoleCommand("destroyentities", nullptr, handler, "Destroys all entities in all worlds");
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
- PlgMgr->BindConsoleCommand("dumpmem", nullptr, " - Dumps all used memory blocks together with their callstacks into memdump.xml");
+ PlgMgr->BindConsoleCommand("dumpmem", nullptr, handler, " - Dumps all used memory blocks together with their callstacks into memdump.xml");
#endif
}
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index 5a2e55feb..4582d6cf4 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -307,7 +307,7 @@ bool cWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
// Checks whether the player is still holding an item
if (!a_Player.GetDraggingItem().IsEmpty())
{
- LOGD("Player holds item! Dropping it...");
+ LOGD("Player is holding an item while closing their window, dropping it as a pickup...");
a_Player.TossHeldItem(a_Player.GetDraggingItem().m_ItemCount);
}
diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp
index e43d749dd..5c08deb0d 100644
--- a/src/WebAdmin.cpp
+++ b/src/WebAdmin.cpp
@@ -2,10 +2,6 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "WebAdmin.h"
-#include "Bindings/WebPlugin.h"
-
-#include "Bindings/PluginManager.h"
-#include "Bindings/Plugin.h"
#include "World.h"
#include "Entities/Player.h"
@@ -87,9 +83,9 @@ public:
// cWebAdmin:
cWebAdmin::cWebAdmin(void) :
+ m_TemplateScript("<webadmin_template>"),
m_IsInitialized(false),
- m_IsRunning(false),
- m_TemplateScript("<webadmin_template>")
+ m_IsRunning(false)
{
}
@@ -106,40 +102,9 @@ cWebAdmin::~cWebAdmin()
-void cWebAdmin::AddPlugin(cWebPlugin * a_Plugin)
-{
- m_Plugins.remove(a_Plugin);
- m_Plugins.push_back(a_Plugin);
-}
-
-
-
-
-
-void cWebAdmin::RemovePlugin(cWebPlugin * a_Plugin)
-{
- m_Plugins.remove(a_Plugin);
-}
-
-
-
-
-
bool cWebAdmin::Init(void)
{
- if (!m_IniFile.ReadFile("webadmin.ini"))
- {
- LOGWARN("Regenerating webadmin.ini, all settings will be reset");
- m_IniFile.AddHeaderComment(" This file controls the webadmin feature of Cuberite");
- m_IniFile.AddHeaderComment(" Username format: [User:*username*]");
- m_IniFile.AddHeaderComment(" Password format: Password=*password*; for example:");
- m_IniFile.AddHeaderComment(" [User:admin]");
- m_IniFile.AddHeaderComment(" Password=admin");
- m_IniFile.SetValue("WebAdmin", "Ports", DEFAULT_WEBADMIN_PORTS);
- m_IniFile.WriteFile("webadmin.ini");
- }
-
- if (!m_IniFile.GetValueSetB("WebAdmin", "Enabled", true))
+ if (!LoadIniFile())
{
// WebAdmin is disabled, bail out faking a success
return true;
@@ -147,31 +112,7 @@ bool cWebAdmin::Init(void)
LOGD("Initialising WebAdmin...");
- // Initialize the WebAdmin template script and load the file
- m_TemplateScript.Create();
- m_TemplateScript.RegisterAPILibs();
- if (!m_TemplateScript.LoadFile(FILE_IO_PREFIX "webadmin/template.lua"))
- {
- LOGWARN("Could not load WebAdmin template \"%s\". WebAdmin disabled!", FILE_IO_PREFIX "webadmin/template.lua");
- m_TemplateScript.Close();
- m_HTTPServer.Stop();
- return false;
- }
-
- // Load the login template, provide a fallback default if not found:
- if (!LoadLoginTemplate())
- {
- LOGWARN("Could not load WebAdmin login template \"%s\", using fallback template.", FILE_IO_PREFIX "webadmin/login_template.html");
-
- // Sets the fallback template:
- m_LoginTemplate = \
- "<h1>Cuberite WebAdmin</h1>" \
- "<center>" \
- "<form method='get' action='webadmin/'>" \
- "<input type='submit' value='Log in'>" \
- "</form>" \
- "</center>";
- }
+ Reload();
// Read the ports to be used:
// Note that historically the ports were stored in the "Port" and "PortsIPv6" values
@@ -224,7 +165,7 @@ void cWebAdmin::Stop(void)
-bool cWebAdmin::LoadLoginTemplate(void)
+bool cWebAdmin::LoadLoginPage(void)
{
cFile File(FILE_IO_PREFIX "webadmin/login_template.html", cFile::fmRead);
if (!File.IsOpen())
@@ -238,7 +179,8 @@ bool cWebAdmin::LoadLoginTemplate(void)
return false;
}
- m_LoginTemplate = TemplateContent;
+ cCSLock Lock(m_CS);
+ m_LoginPage = TemplateContent;
return true;
}
@@ -246,6 +188,89 @@ bool cWebAdmin::LoadLoginTemplate(void)
+void cWebAdmin::RemoveAllPluginWebTabs(const AString & a_PluginName)
+{
+ cCSLock lock(m_CS);
+ m_WebTabs.erase(std::remove_if(m_WebTabs.begin(), m_WebTabs.end(), [=](cWebTabPtr a_CBWebTab)
+ {
+ return (a_CBWebTab->m_PluginName == a_PluginName);
+ }),
+ m_WebTabs.end()
+ );
+}
+
+
+
+
+
+void cWebAdmin::Reload(void)
+{
+ cCSLock lock(m_CS);
+ if (!LoadIniFile())
+ {
+ // We are asked to disable the webadmin, cannot do that, so warn the admin:
+ LOGWARNING(
+ "WebAdmin was previously enabled and now the settings say to disable it."
+ " This will not take effect until you restart the server."
+ );
+ }
+
+ // Initialize the WebAdmin template script and reload the file:
+ if (m_TemplateScript.IsValid())
+ {
+ m_TemplateScript.Close();
+ }
+ m_TemplateScript.Create();
+ m_TemplateScript.RegisterAPILibs();
+ if (!m_TemplateScript.LoadFile(FILE_IO_PREFIX "webadmin/template.lua"))
+ {
+ LOGWARN("Could not load WebAdmin template \"%s\". WebAdmin will not work properly!", FILE_IO_PREFIX "webadmin/template.lua");
+ m_TemplateScript.Close();
+ }
+
+ // Load the login template, provide a fallback default if not found:
+ if (!LoadLoginPage())
+ {
+ LOGWARN("Could not load WebAdmin login page \"%s\", using fallback template.", FILE_IO_PREFIX "webadmin/login_template.html");
+
+ // Set the fallback:
+ m_LoginPage = \
+ "<h1>Cuberite WebAdmin</h1>" \
+ "<center>" \
+ "<form method='get' action='webadmin/'>" \
+ "<input type='submit' value='Log in'>" \
+ "</form>" \
+ "</center>";
+ }
+}
+
+
+
+
+
+bool cWebAdmin::LoadIniFile(void)
+{
+ m_IniFile.Clear();
+ if (!m_IniFile.ReadFile("webadmin.ini"))
+ {
+ LOGWARN("Regenerating webadmin.ini, all settings will be reset");
+ m_IniFile.AddHeaderComment(" This file controls the webadmin feature of Cuberite");
+ m_IniFile.AddHeaderComment(" It specifies whether webadmin is enabled, and what logins are allowed. ");
+ m_IniFile.AddHeaderComment(" Username format: [User:*username*]");
+ m_IniFile.AddHeaderComment(" Password format: Password=*password*; for example:");
+ m_IniFile.AddHeaderComment(" [User:admin]");
+ m_IniFile.AddHeaderComment(" Password=admin");
+ m_IniFile.SetValue("WebAdmin", "Ports", DEFAULT_WEBADMIN_PORTS);
+ m_IniFile.WriteFile("webadmin.ini");
+ }
+
+ return m_IniFile.GetValueSetB("WebAdmin", "Enabled", true);
+}
+
+
+
+
+
void cWebAdmin::HandleWebadminRequest(cHTTPServerConnection & a_Connection, cHTTPIncomingRequest & a_Request)
{
if (!a_Request.HasAuth())
@@ -255,17 +280,20 @@ void cWebAdmin::HandleWebadminRequest(cHTTPServerConnection & a_Connection, cHTT
}
// Check auth:
- AString UserPassword = m_IniFile.GetValue("User:" + a_Request.GetAuthUsername(), "Password", "");
- if ((UserPassword == "") || (a_Request.GetAuthPassword() != UserPassword))
{
- a_Connection.SendNeedAuth("Cuberite WebAdmin - bad username or password");
- return;
+ cCSLock Lock(m_CS);
+ AString UserPassword = m_IniFile.GetValue("User:" + a_Request.GetAuthUsername(), "Password", "");
+ if ((UserPassword == "") || (a_Request.GetAuthPassword() != UserPassword))
+ {
+ a_Connection.SendNeedAuth("Cuberite WebAdmin - bad username or password");
+ return;
+ }
}
// Check if the contents should be wrapped in the template:
auto BareURL = a_Request.GetURLPath();
ASSERT(BareURL.length() > 0);
- bool ShouldWrapInTemplate = ((BareURL.length() > 1) && (BareURL[1] != '~'));
+ bool ShouldWrapInTemplate = (!BareURL.empty() && (BareURL[1] != '~'));
// Retrieve the request data:
auto Data = std::static_pointer_cast<cWebadminRequestData>(a_Request.GetUserData());
@@ -312,6 +340,7 @@ void cWebAdmin::HandleWebadminRequest(cHTTPServerConnection & a_Connection, cHTT
// Try to get the template from the Lua template script
if (ShouldWrapInTemplate)
{
+ cCSLock Lock(m_CS);
if (m_TemplateScript.Call("ShowPage", this, &TemplateRequest, cLuaState::Return, Template))
{
cHTTPOutgoingResponse Resp;
@@ -325,59 +354,12 @@ void cWebAdmin::HandleWebadminRequest(cHTTPServerConnection & a_Connection, cHTT
return;
}
- AString BaseURL = GetBaseURL(BareURL);
- AString Menu;
- Template = "{CONTENT}";
- AString FoundPlugin;
-
- for (PluginList::iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr)
- {
- cWebPlugin * WebPlugin = *itr;
- std::list< std::pair<AString, AString> > NameList = WebPlugin->GetTabNames();
- for (std::list< std::pair<AString, AString> >::iterator Names = NameList.begin(); Names != NameList.end(); ++Names)
- {
- Menu += "<li><a href='" + BaseURL + WebPlugin->GetWebTitle().c_str() + "/" + (*Names).second + "'>" + (*Names).first + "</a></li>";
- }
- }
-
- sWebAdminPage Page = GetPage(TemplateRequest.Request);
- AString Content = Page.Content;
- FoundPlugin = Page.PluginName;
- if (!Page.TabName.empty())
- {
- FoundPlugin += " - " + Page.TabName;
- }
-
- if (FoundPlugin.empty()) // Default page
- {
- Content = GetDefaultPage();
- }
-
- int MemUsageKiB = cRoot::GetPhysicalRAMUsage();
- if (MemUsageKiB > 0)
- {
- ReplaceString(Template, "{MEM}", Printf("%.02f", static_cast<double>(MemUsageKiB) / 1024));
- ReplaceString(Template, "{MEMKIB}", Printf("%d", MemUsageKiB));
- }
- else
- {
- ReplaceString(Template, "{MEM}", "unknown");
- ReplaceString(Template, "{MEMKIB}", "unknown");
- }
- ReplaceString(Template, "{USERNAME}", a_Request.GetAuthUsername());
- ReplaceString(Template, "{MENU}", Menu);
- ReplaceString(Template, "{PLUGIN_NAME}", FoundPlugin);
- ReplaceString(Template, "{CONTENT}", Content);
- ReplaceString(Template, "{TITLE}", "Cuberite");
-
- AString NumChunks;
- Printf(NumChunks, "%d", cRoot::Get()->GetTotalChunkCount());
- ReplaceString(Template, "{NUMCHUNKS}", NumChunks);
-
- cHTTPOutgoingResponse Resp;
- Resp.SetContentType("text/html");
- a_Connection.Send(Resp);
- a_Connection.Send(Template.c_str(), Template.length());
+ // Send the un-decorated page content:
+ auto page = GetPage(TemplateRequest.Request);
+ cHTTPOutgoingResponse resp;
+ resp.SetContentType(page.ContentType);
+ a_Connection.Send(resp);
+ a_Connection.Send(page.Content.c_str(), page.Content.length());
a_Connection.FinishResponse();
}
@@ -392,7 +374,7 @@ void cWebAdmin::HandleRootRequest(cHTTPServerConnection & a_Connection, cHTTPInc
cHTTPOutgoingResponse Resp;
Resp.SetContentType("text/html");
a_Connection.Send(Resp);
- a_Connection.Send(m_LoginTemplate);
+ a_Connection.Send(m_LoginPage);
a_Connection.FinishResponse();
}
@@ -406,7 +388,7 @@ void cWebAdmin::HandleFileRequest(cHTTPServerConnection & a_Connection, cHTTPInc
std::replace(FileURL.begin(), FileURL.end(), '\\', '/');
// Remove all leading backslashes:
- if (FileURL[0] == '/')
+ if (!FileURL.empty() && (FileURL[0] == '/'))
{
size_t FirstCharToRead = FileURL.find_first_not_of('/');
if (FirstCharToRead != AString::npos)
@@ -418,8 +400,9 @@ void cWebAdmin::HandleFileRequest(cHTTPServerConnection & a_Connection, cHTTPInc
// Remove all "../" strings:
ReplaceString(FileURL, "../", "");
- bool LoadedSuccessfull = false;
+ // Read the file contents and guess its mime-type, based on the extension:
AString Content = "<h2>404 Not Found</h2>";
+ AString ContentType;
AString Path = Printf(FILE_IO_PREFIX "webadmin/files/%s", FileURL.c_str());
if (cFile::IsFile(Path))
{
@@ -427,18 +410,17 @@ void cWebAdmin::HandleFileRequest(cHTTPServerConnection & a_Connection, cHTTPInc
AString FileContent;
if (File.IsOpen() && (File.ReadRestOfFile(FileContent) != -1))
{
- LoadedSuccessfull = true;
- Content = FileContent;
+ std::swap(Content, FileContent);
+ size_t LastPointPosition = Path.find_last_of('.');
+ if (LastPointPosition != AString::npos)
+ {
+ ContentType = GetContentTypeFromFileExt(Path.substr(LastPointPosition + 1));
+ }
}
}
-
- // Find content type (The currently method is very bad. We should change it later)
- AString ContentType = "text/html";
- size_t LastPointPosition = Path.find_last_of('.');
- if (LoadedSuccessfull && (LastPointPosition != AString::npos) && (LastPointPosition < Path.length()))
+ if (ContentType.empty())
{
- AString FileExtension = Path.substr(LastPointPosition + 1);
- ContentType = GetContentTypeFromFileExt(FileExtension);
+ ContentType = "application/unknown";
}
// Send the response:
@@ -456,32 +438,36 @@ void cWebAdmin::HandleFileRequest(cHTTPServerConnection & a_Connection, cHTTPInc
AString cWebAdmin::GetContentTypeFromFileExt(const AString & a_FileExtension)
{
static bool IsInitialized = false;
- static std::map<AString, AString> ContentTypeMap;
+ static AStringMap ContentTypeMap;
if (!IsInitialized)
{
// Initialize the ContentTypeMap:
- ContentTypeMap["png"] = "image/png";
- ContentTypeMap["fif"] = "image/fif";
- ContentTypeMap["gif"] = "image/gif";
- ContentTypeMap["jpeg"] = "image/jpeg";
- ContentTypeMap["jpg"] = "image/jpeg";
- ContentTypeMap["jpe"] = "image/jpeg";
- ContentTypeMap["tiff"] = "image/tiff";
- ContentTypeMap["ico"] = "image/ico";
- ContentTypeMap["csv"] = "image/comma-separated-values";
- ContentTypeMap["css"] = "text/css";
- ContentTypeMap["js"] = "text/javascript";
- ContentTypeMap["txt"] = "text/plain";
- ContentTypeMap["rtx"] = "text/richtext";
- ContentTypeMap["xml"] = "text/xml";
- }
-
- AString FileExtension = StrToLower(a_FileExtension);
- if (ContentTypeMap.find(a_FileExtension) == ContentTypeMap.end())
- {
- return "text/html";
- }
- return ContentTypeMap[FileExtension];
+ ContentTypeMap["png"] = "image/png";
+ ContentTypeMap["fif"] = "image/fif";
+ ContentTypeMap["gif"] = "image/gif";
+ ContentTypeMap["jpeg"] = "image/jpeg";
+ ContentTypeMap["jpg"] = "image/jpeg";
+ ContentTypeMap["jpe"] = "image/jpeg";
+ ContentTypeMap["tiff"] = "image/tiff";
+ ContentTypeMap["ico"] = "image/ico";
+ ContentTypeMap["csv"] = "text/csv";
+ ContentTypeMap["css"] = "text/css";
+ ContentTypeMap["js"] = "text/javascript";
+ ContentTypeMap["txt"] = "text/plain";
+ ContentTypeMap["rtx"] = "text/richtext";
+ ContentTypeMap["rtf"] = "text/richtext";
+ ContentTypeMap["xml"] = "text/xml";
+ ContentTypeMap["html"] = "text/html";
+ ContentTypeMap["htm"] = "text/html";
+ ContentTypeMap["xhtml"] = "application/xhtml+xml"; // Not recomended for IE6, but no-one uses that anymore
+ }
+
+ auto itr = ContentTypeMap.find(StrToLower(a_FileExtension));
+ if (itr == ContentTypeMap.end())
+ {
+ return AString();
+ }
+ return itr->second;
}
@@ -490,86 +476,93 @@ AString cWebAdmin::GetContentTypeFromFileExt(const AString & a_FileExtension)
sWebAdminPage cWebAdmin::GetPage(const HTTPRequest & a_Request)
{
- sWebAdminPage Page;
- AStringVector Split = StringSplit(a_Request.Path, "/");
+ sWebAdminPage page;
+ auto split = StringSplit(a_Request.Path, "/");
+
+ // If no specific page was requested, return an empty object:
+ if (split.size() <= 2)
+ {
+ return page;
+ }
- // Find the plugin that corresponds to the requested path
- AString FoundPlugin;
- if (Split.size() > 1)
+ // Find the WebTab handler responsible for the request:
+ cWebTabPtr tab;
{
- for (PluginList::iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr)
+ cCSLock Lock(m_CS);
+ for (auto & wt: m_WebTabs)
{
- if ((*itr)->GetWebTitle() == Split[1])
+ if (
+ (wt->m_PluginName == split[1]) &&
+ (wt->m_UrlPath == split[2])
+ )
{
- Page.Content = (*itr)->HandleWebRequest(a_Request);
- cWebPlugin * WebPlugin = *itr;
- FoundPlugin = WebPlugin->GetWebTitle();
- AString TabName = WebPlugin->GetTabNameForRequest(a_Request).first;
- Page.PluginName = FoundPlugin;
- Page.TabName = TabName;
+ tab = wt;
break;
}
+ } // for wt - m_WebTabs[]
+ }
+
+ // If a WebTab handler was found, call it:
+ if (tab != nullptr)
+ {
+ page.ContentType = "text/html"; // Default to HTML content type, unless overridden by a plugin
+ if (!tab->m_Callback->Call(a_Request, split[1], page.Content, page.ContentType))
+ {
+ page.Content = GetHTMLEscapedString(Printf(
+ "WebTab callback for plugin %s, page %s has failed.",
+ tab->m_PluginName.c_str(), tab->m_Title.c_str()
+ ));
}
+ page.PluginName = tab->m_PluginName;
+ page.TabTitle = tab->m_Title;
+ page.TabUrlPath = split[1];
}
- // Return the page contents
- return Page;
+ return page;
}
-AString cWebAdmin::GetDefaultPage(void)
+AString cWebAdmin::GetBaseURL(const AString & a_URL)
{
- AString Content;
- Content += "<h4>Server Name:</h4>";
- Content += "<p>" + AString( cRoot::Get()->GetServer()->GetServerID()) + "</p>";
+ return GetBaseURL(StringSplit(a_URL, "/"));
+}
- // Display a list of all plugins:
- Content += "<h4>Plugins:</h4><ul>";
- struct cPluginCallback:
- public cPluginManager::cPluginCallback
- {
- AString & m_Content;
- cPluginCallback(AString & a_Content):
- m_Content(a_Content)
- {
- }
- virtual bool Item(cPlugin * a_Plugin) override
- {
- if (a_Plugin->IsLoaded())
- {
- AppendPrintf(m_Content, "<li>%s V.%i</li>", a_Plugin->GetName().c_str(), a_Plugin->GetVersion());
- }
- return false;
- }
- } Callback(Content);
- cPluginManager::Get()->ForEachPlugin(Callback);
- Content += "</ul>";
- // Display a list of all players:
- Content += "<h4>Players:</h4><ul>";
- cPlayerAccum PlayerAccum;
- cWorld * World = cRoot::Get()->GetDefaultWorld(); // TODO - Create a list of worlds and players
- if (World != nullptr)
- {
- World->ForEachPlayer(PlayerAccum);
- Content.append(PlayerAccum.m_Contents);
- }
- Content += "</ul><br>";
- return Content;
+
+void cWebAdmin::AddWebTab(
+ const AString & a_Title,
+ const AString & a_UrlPath,
+ const AString & a_PluginName,
+ SharedPtr<cWebAdmin::cWebTabCallback> a_Callback
+)
+{
+ cCSLock lock(m_CS);
+ m_WebTabs.emplace_back(std::make_shared<cWebTab>(a_Title, a_UrlPath, a_PluginName, a_Callback));
}
-AString cWebAdmin::GetBaseURL(const AString & a_URL)
+bool cWebAdmin::DelWebTab(const AString & a_UrlPath)
{
- return GetBaseURL(StringSplit(a_URL, "/"));
+ cCSLock lock(m_CS);
+ for (auto itr = m_WebTabs.begin(), end = m_WebTabs.end(); itr != end; ++itr)
+ {
+ if ((*itr)->m_UrlPath == a_UrlPath)
+ {
+ m_WebTabs.erase(itr);
+ return true;
+ }
+ } // for itr - m_WebTabs[]
+
+ // Not found:
+ return false;
}
diff --git a/src/WebAdmin.h b/src/WebAdmin.h
index 5e48f597c..b76ca6df8 100644
--- a/src/WebAdmin.h
+++ b/src/WebAdmin.h
@@ -89,14 +89,14 @@ struct HTTPTemplateRequest
-// tolua_begin
struct sWebAdminPage
{
AString Content;
AString PluginName;
- AString TabName;
+ AString TabTitle;
+ AString TabUrlPath;
+ AString ContentType;
};
-// tolua_end
@@ -111,7 +111,49 @@ class cWebAdmin :
public:
// tolua_end
- typedef std::list< cWebPlugin* > PluginList;
+ /** Interface for getting the content of a single WebTab. */
+ class cWebTabCallback abstract
+ {
+ public:
+ // Force a virtual destructor in descendants
+ virtual ~cWebTabCallback() {}
+
+ /** Returns the contents for the specified request.
+ Returns true if the call was successful, false on an error.
+ a_Request is the full HTTP request object, as received from the client.
+ a_UrlPath is the UrlPath of the WebTab registered for this request, as parsed from a_Request.
+ Descendants should fill a_Content with the page contents
+ and optionally set a_ContentType [defaults to "text/html"] */
+ virtual bool Call(
+ const HTTPRequest & a_Request,
+ const AString & a_UrlPath,
+ AString & a_Content,
+ AString & a_ContentType
+ ) = 0;
+ };
+
+
+ /** Container for a single web tab.
+ Each web tab has a title, URL path and an associated plugin's name.
+ Each web tab is registered with a callback to provide the content. */
+ class cWebTab
+ {
+ public:
+ AString m_Title;
+ AString m_UrlPath;
+ AString m_PluginName;
+ SharedPtr<cWebTabCallback> m_Callback;
+
+ cWebTab(const AString & a_Title, const AString & a_UrlPath, const AString & a_PluginName, SharedPtr<cWebTabCallback> a_Callback):
+ m_Title(a_Title),
+ m_UrlPath(a_UrlPath),
+ m_PluginName(a_PluginName),
+ m_Callback(a_Callback)
+ {
+ }
+ };
+ typedef SharedPtr<cWebTab> cWebTabPtr;
+ typedef std::vector<cWebTabPtr> cWebTabPtrs;
cWebAdmin(void);
@@ -120,81 +162,115 @@ public:
/** Initializes the object. Returns true if successfully initialized and ready to start */
bool Init(void);
- /** Starts the HTTP server taking care of the admin. Returns true if successful */
+ /** Starts the HTTP server taking care of the webadmin. Returns true if successful */
bool Start(void);
/** Stops the HTTP server, if it was started. */
void Stop(void);
- /** Loads the login template. Returns true if the loading succeeds, false if not. */
- bool LoadLoginTemplate(void);
-
- void AddPlugin(cWebPlugin * a_Plugin);
- void RemovePlugin(cWebPlugin * a_Plugin);
+ /** Loads the login template into m_LoginPage.
+ Returns true if the loading succeeds, false if not. */
+ bool LoadLoginPage(void);
- // TODO: Convert this to the auto-locking callback mechanism used for looping players in worlds and such
- PluginList GetPlugins() const { return m_Plugins; } // >> EXPORTED IN MANUALBINDINGS <<
+ /** Returns a copy of all the registered web tabs.
+ Exported to Lua in ManualBindings.cpp. */
+ cWebTabPtrs GetAllWebTabs(void) { return m_WebTabs; }
- // tolua_begin
+ /** Removes all WebTabs registered by the specified plugin. */
+ void RemoveAllPluginWebTabs(const AString & a_PluginName);
+ /** Returns the (inner) page contents for the specified request.
+ Calls the appropriate WebTab handler to get the contents.
+ Exported to Lua in ManualBindings.cpp. */
sWebAdminPage GetPage(const HTTPRequest & a_Request);
- /** Returns the contents of the default page - the list of plugins and players */
- AString GetDefaultPage(void);
+ // tolua_begin
- /** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */
- AString GetBaseURL(const AString & a_URL);
+ /** Reloads m_IniFile, m_LoginPage and m_TemplateScript.
+ Note that reloading will not change the "enabled" state of the server, and it will not update listening ports. */
+ void Reload(void);
- /** Returns the list of ports used for the webadmin. */
+ /** Returns the list of ports on which the webadmin is configured to listen. */
AString GetPorts(void) const { return StringsConcat(m_Ports, ','); }
-
- /** OBSOLETE: Returns the list of IPv4 ports used for the webadmin.
- Currently there is no distinction between IPv4 and IPv6; use GetPorts() instead. */
- AString GetIPv4Ports(void) const { return GetPorts(); }
-
- /** OBSOLETE: Returns the list of IPv6 ports used for the webadmin.
- Currently there is no distinction between IPv4 and IPv6; use GetPorts() instead. */
- AString GetIPv6Ports(void) const { return GetPorts(); }
-
// tolua_end
- /** Escapes text passed into it, so it can be embedded into html. */
+ /** Adds a new WebTab handler.
+ a_Title is the display title of the tab
+ a_UrlPath is the part of the URL that uniquely identifies this tab.
+ a_PluginName is the display name of the plugin creating this tab.
+ a_Callback is used to provide the actual WebTab contents, when requested.
+ Exported in ManualBindings.cpp. */
+ void AddWebTab(
+ const AString & a_Title,
+ const AString & a_UrlPath,
+ const AString & a_PluginName,
+ SharedPtr<cWebTabCallback> a_Callback
+ );
+
+ /** Removes the WebTab with the specified URL path.
+ Returns true if WebTab was found and removed, false if not found.
+ Exported in ManualBindings.cpp */
+ bool DelWebTab(const AString & a_UrlPath);
+
+ /** Escapes text passed into it, so it can be embedded into html.
+ Exported to Lua in ManualBindings.cpp. */
static AString GetHTMLEscapedString(const AString & a_Input);
- /** Escapes the string for use in an URL */
+ /** Escapes the string for use in an URL
+ Exported to Lua in ManualBindings.cpp. */
static AString GetURLEncodedString(const AString & a_Input);
+ /** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style).
+ Exported to Lua in ManualBindings.cpp. */
+ static AString GetBaseURL(const AString & a_URL);
+
/** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */
static AString GetBaseURL(const AStringVector & a_URLSplit);
- /** Returns the content type from the file extension. If the extension isn't in the list, the function returns "text/html" */
+ /** Returns the content type from the file extension.
+ If the extension isn't in the list, the function returns an empty string.
+ Exported to Lua in ManualBindings.cpp. */
static AString GetContentTypeFromFileExt(const AString & a_FileExtension);
protected:
+ /** Protects m_WebTabs, m_TemplateScript, m_LoginTemplate and m_IniFile against multithreaded access. */
+ cCriticalSection m_CS;
+
+ /** All registered WebTab handlers.
+ Protected against multithreaded access by m_CS. */
+ cWebTabPtrs m_WebTabs;
+
+ /** The Lua template script to provide templates.
+ Protected against multithreaded access by m_CS. */
+ cLuaState m_TemplateScript;
+
+ /** The HTML page that provides the login.
+ Protected against multithreaded access by m_CS. */
+ AString m_LoginPage;
+
+ /** The webadmin.ini file, used for the settings and allowed logins.
+ Protected against multithreaded access by m_CS. */
+ cIniFile m_IniFile;
+
/** Set to true if Init() succeeds and the webadmin isn't to be disabled */
bool m_IsInitialized;
/** Set to true if Start() succeeds in starting the server, reset back to false in Stop(). */
bool m_IsRunning;
- /** The webadmin.ini file, used for the settings and allowed logins */
- cIniFile m_IniFile;
-
- PluginList m_Plugins;
-
/** The ports on which the webadmin is running. */
AStringVector m_Ports;
- /** The Lua template script to provide templates: */
- cLuaState m_TemplateScript;
-
- /** The template that provides the login site: */
- AString m_LoginTemplate;
-
/** The HTTP server which provides the underlying HTTP parsing, serialization and events */
cHTTPServer m_HTTPServer;
+
+ /** Loads webadmin.ini into m_IniFile.
+ Creates a default file if it doesn't exist.
+ Returns true if webadmin is enabled, false if disabled. */
+ bool LoadIniFile(void);
+
/** Handles requests coming to the "/webadmin" or "/~webadmin" URLs */
void HandleWebadminRequest(cHTTPServerConnection & a_Connection, cHTTPIncomingRequest & a_Request);