summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattes D <github@xoft.cz>2016-03-21 10:40:38 +0100
committerMattes D <github@xoft.cz>2016-03-21 10:40:38 +0100
commitfa53e98419152a83b2a74c5ea45a60449abc59c2 (patch)
tree766f4703a8c30a01bfc5148fe54c6d6b4a3e3cc7 /src
parentMerge pull request #3084 from cuberite/seadragon91-patch-1 (diff)
parentRevert "Lua callback" (diff)
downloadcuberite-fa53e98419152a83b2a74c5ea45a60449abc59c2.tar
cuberite-fa53e98419152a83b2a74c5ea45a60449abc59c2.tar.gz
cuberite-fa53e98419152a83b2a74c5ea45a60449abc59c2.tar.bz2
cuberite-fa53e98419152a83b2a74c5ea45a60449abc59c2.tar.lz
cuberite-fa53e98419152a83b2a74c5ea45a60449abc59c2.tar.xz
cuberite-fa53e98419152a83b2a74c5ea45a60449abc59c2.tar.zst
cuberite-fa53e98419152a83b2a74c5ea45a60449abc59c2.zip
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/AllToLua.pkg1
-rw-r--r--src/Bindings/CMakeLists.txt3
-rw-r--r--src/Bindings/LuaState.cpp220
-rw-r--r--src/Bindings/LuaState.h117
-rw-r--r--src/Bindings/LuaWindow.cpp95
-rw-r--r--src/Bindings/LuaWindow.h72
-rw-r--r--src/Bindings/ManualBindings.cpp461
-rw-r--r--src/Bindings/ManualBindings_World.cpp105
-rw-r--r--src/Bindings/PluginLua.cpp1191
-rw-r--r--src/Bindings/PluginLua.h86
-rw-r--r--src/Bindings/PluginManager.cpp17
-rw-r--r--src/Bindings/PluginManager.h3
-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/UI/Window.cpp2
-rw-r--r--src/WebAdmin.cpp415
-rw-r--r--src/WebAdmin.h158
18 files changed, 1925 insertions, 1259 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 6ca9c8658..991ed0ddd 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -38,6 +38,7 @@ $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 4f25f2cf4..10cda1efb 100644
--- a/src/Bindings/CMakeLists.txt
+++ b/src/Bindings/CMakeLists.txt
@@ -23,6 +23,7 @@ SET (SRCS
Plugin.cpp
PluginLua.cpp
PluginManager.cpp
+ WebPlugin.cpp
)
SET (HDRS
@@ -43,6 +44,7 @@ SET (HDRS
Plugin.h
PluginLua.h
PluginManager.h
+ WebPlugin.h
tolua++.h
)
@@ -64,6 +66,7 @@ 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/LuaState.cpp b/src/Bindings/LuaState.cpp
index 98507e96c..200878cf7 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -20,10 +20,6 @@ extern "C"
#include "../Entities/Entity.h"
#include "../BlockEntities/BlockEntity.h"
-
-
-
-
// fwd: "SQLite/lsqlite3.c"
extern "C"
{
@@ -43,10 +39,6 @@ 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";
-
@@ -122,101 +114,6 @@ cLuaStateTracker & cLuaStateTracker::Get(void)
////////////////////////////////////////////////////////////////////////////////
-// cLuaState::cCallback:
-
-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:
- a_LuaState.TrackCallback(*this);
-
- // Store the new callback:
- cCSLock Lock(m_CS);
- m_Ref.RefStack(a_LuaState, a_StackPos);
- return true;
-}
-
-
-
-
-
-void cLuaState::cCallback::Clear(void)
-{
- // Free the callback reference:
- lua_State * luaState = nullptr;
- {
- cCSLock Lock(m_CS);
- if (!m_Ref.IsValid())
- {
- return;
- }
- luaState = m_Ref.GetLuaState();
- m_Ref.UnRef();
- }
-
- // Remove from LuaState's callback-tracking:
- cLuaState(luaState).UntrackCallback(*this);
-}
-
-
-
-
-
-bool cLuaState::cCallback::IsValid(void)
-{
- cCSLock lock(m_CS);
- return m_Ref.IsValid();
-}
-
-
-
-
-
-bool cLuaState::cCallback::IsSameLuaState(cLuaState & a_LuaState)
-{
- cCSLock lock(m_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)
-{
- cCSLock Lock(m_CS);
- if (!m_Ref.IsValid())
- {
- LOGD("%s: Invalidating an already invalid callback at %p, this should not happen",
- __FUNCTION__, reinterpret_cast<void *>(this)
- );
- return;
- }
- m_Ref.UnRef();
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
// cLuaState:
cLuaState::cLuaState(const AString & a_SubsystemName) :
@@ -273,10 +170,6 @@ 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);
}
@@ -313,16 +206,6 @@ 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;
@@ -938,18 +821,6 @@ 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;
@@ -976,24 +847,6 @@ 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)
-{
- return a_Callback->RefStack(*this, a_StackPos);
-}
-
-
-
-
-
bool cLuaState::GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result)
{
if (lua_isnumber(m_LuaState, a_StackPos))
@@ -1678,7 +1531,7 @@ int cLuaState::CopyStackFrom(cLuaState & a_SrcLuaState, int a_SrcStart, int a_Sr
LOGWARNING("%s: Unsupported value: '%s' at stack position %d. Can only copy numbers, strings, bools and classes!",
__FUNCTION__, lua_typename(a_SrcLuaState, t), i
);
- a_SrcLuaState.LogStackValues("Stack where copying failed:");
+ a_SrcLuaState.LogStack("Stack where copying failed:");
lua_pop(m_LuaState, i - a_SrcStart);
return -1;
}
@@ -1705,16 +1558,16 @@ void cLuaState::ToString(int a_StackPos, AString & a_String)
-void cLuaState::LogStackValues(const char * a_Header)
+void cLuaState::LogStack(const char * a_Header)
{
- LogStackValues(m_LuaState, a_Header);
+ LogStack(m_LuaState, a_Header);
}
-void cLuaState::LogStackValues(lua_State * a_LuaState, const char * a_Header)
+void cLuaState::LogStack(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:");
@@ -1739,21 +1592,6 @@ void cLuaState::LogStackValues(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));
@@ -1788,50 +1626,6 @@ 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:
@@ -1887,7 +1681,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);
}
@@ -1898,9 +1692,11 @@ 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 0509b09ed..215980033 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -80,20 +80,8 @@ 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:
- lua_State * m_LuaState;
+ cLuaState * m_LuaState;
int m_Ref;
// Remove the copy-constructor:
@@ -124,76 +112,6 @@ 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().
- 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) = default;
-
- ~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)
- {
- cCSLock Lock(m_CS);
- if (!m_Ref.IsValid())
- {
- return false;
- }
- cLuaState(m_Ref.GetLuaState()).Call(m_Ref, std::forward<Args>(args)...);
- return true;
- }
-
- /** 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. */
- cCallback(const cCallback &) = delete;
-
- /** This class cannot be moved, because it is tracked in the LuaState by-ptr. */
- cCallback(cCallback &&) = delete;
- };
- typedef SharedPtr<cCallback> cCallbackPtr;
-
-
/** A dummy class that's used only to delimit function args from return values for cLuaState::Call() */
class cRet
{
@@ -343,16 +261,11 @@ 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, cPluginManager::CommandResult & a_Result);
bool GetStackValue(int a_StackPos, cRef & a_Ref);
bool GetStackValue(int a_StackPos, double & a_Value);
@@ -515,14 +428,10 @@ 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 LogStackValues(const char * a_Header = nullptr);
+ void LogStack(const char * a_Header = nullptr);
/** Logs all the elements' types on the API stack, with an optional header for the listing. */
- 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);
+ static void LogStack(lua_State * a_LuaState, const char * a_Header = nullptr);
protected:
@@ -532,7 +441,8 @@ protected:
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) */
@@ -541,15 +451,6 @@ 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)
@@ -632,14 +533,6 @@ 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/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp
index bf3f7cfde..706397a27 100644
--- a/src/Bindings/LuaWindow.cpp
+++ b/src/Bindings/LuaWindow.cpp
@@ -15,13 +15,14 @@
////////////////////////////////////////////////////////////////////////////////
// cLuaWindow:
-cLuaWindow::cLuaWindow(cLuaState & a_LuaState, cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title) :
- Super(a_WindowType, a_Title),
+cLuaWindow::cLuaWindow(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_LuaState(a_LuaState.QueryCanonLuaState())
+ m_Plugin(nullptr),
+ m_LuaRef(LUA_REFNIL),
+ m_OnClosingFnRef(LUA_REFNIL),
+ m_OnSlotChangedFnRef(LUA_REFNIL)
{
- 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));
@@ -66,42 +67,62 @@ cLuaWindow::~cLuaWindow()
-void cLuaWindow::SetOnClosing(cLuaState::cCallbackPtr a_OnClosing)
+void cLuaWindow::SetLuaRef(cPluginLua * a_Plugin, int a_LuaRef)
{
- // Only one Lua state can be a cLuaWindow object callback:
- ASSERT(a_OnClosing->IsSameLuaState(*m_LuaState));
+ // 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;
+}
+
+
+
- // Store the new reference, releasing the old one if appropriate:
- m_OnClosing = a_OnClosing;
+
+bool cLuaWindow::IsLuaReferenced(void) const
+{
+ return ((m_Plugin != nullptr) && (m_LuaRef != LUA_REFNIL));
}
-void cLuaWindow::SetOnSlotChanged(cLuaState::cCallbackPtr a_OnSlotChanged)
+void cLuaWindow::SetOnClosing(cPluginLua * a_Plugin, int a_FnRef)
{
- // Only one Lua state can be a cLuaWindow object callback:
- ASSERT(a_OnSlotChanged->IsSameLuaState(*m_LuaState));
+ // 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));
- // Store the new reference, releasing the old one if appropriate:
- m_OnSlotChanged = a_OnSlotChanged;
+ // 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;
}
-void cLuaWindow::OpenedByPlayer(cPlayer & a_Player)
+void cLuaWindow::SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef)
{
- // 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)
+ // 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)
{
- m_LuaRef.CreateFromObject(*m_LuaState, this);
+ m_Plugin->Unreference(m_OnSlotChangedFnRef);
}
- ++m_PlayerCount;
- Super::OpenedByPlayer(a_Player);
+ // Store the new reference
+ m_Plugin = a_Plugin;
+ m_OnSlotChangedFnRef = a_FnRef;
}
@@ -111,27 +132,17 @@ void cLuaWindow::OpenedByPlayer(cPlayer & a_Player)
bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
{
// First notify the plugin through the registered callback:
- if (m_OnClosing != nullptr)
+ if (m_OnClosingFnRef != LUA_REFNIL)
{
- 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
- )
+ ASSERT(m_Plugin != nullptr);
+ if (m_Plugin->CallbackWindowClosing(m_OnClosingFnRef, *this, a_Player, a_CanRefuse))
{
// The callback disagrees (the higher levels check the CanRefuse flag compliance)
return false;
}
}
- // 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);
+ return super::ClosedByPlayer(a_Player, a_CanRefuse);
}
@@ -140,7 +151,13 @@ bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
void cLuaWindow::Destroy(void)
{
- Super::Destroy();
+ super::Destroy();
+
+ if ((m_LuaRef != LUA_REFNIL) && (m_Plugin != nullptr))
+ {
+ // The object is referenced by Lua, un-reference it
+ m_Plugin->Unreference(m_LuaRef);
+ }
// Lua will take care of this object, it will garbage-collect it, so we must not delete it!
m_IsDestroyed = false;
@@ -161,7 +178,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);
}
@@ -177,9 +194,9 @@ void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
}
// If an OnSlotChanged callback has been registered, call it:
- if (m_OnSlotChanged != nullptr)
+ if (m_OnSlotChangedFnRef != LUA_REFNIL)
{
- m_OnSlotChanged->Call(this, a_SlotNum);
+ m_Plugin->CallbackWindowSlotChanged(m_OnSlotChangedFnRef, *this, a_SlotNum);
}
}
diff --git a/src/Bindings/LuaWindow.h b/src/Bindings/LuaWindow.h
index 2a16d91ed..f292a5154 100644
--- a/src/Bindings/LuaWindow.h
+++ b/src/Bindings/LuaWindow.h
@@ -9,8 +9,6 @@
#pragma once
-#include <atomic>
-#include "LuaState.h"
#include "../UI/Window.h"
#include "../ItemGrid.h"
@@ -18,30 +16,35 @@
+// 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.
-- 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.
-*/
+- 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. */
// tolua_begin
class cLuaWindow :
public cWindow
// tolua_end
, public cItemGrid::cListener
-{ // tolua_export
- typedef cWindow Super;
+ // tolua_begin
+{
+ typedef cWindow super;
public:
- /** 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);
+ /** 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);
- // tolua_begin
virtual ~cLuaWindow();
/** Returns the internal representation of the contents that are manipulated by Lua */
@@ -49,37 +52,36 @@ public:
// tolua_end
- /** Sets the Lua callback function to call when the window is about to close */
- void SetOnClosing(cLuaState::cCallbackPtr a_OnClosing);
+ /** 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);
- /** Sets the Lua callback function to call when a slot is changed */
- void SetOnSlotChanged(cLuaState::cCallbackPtr a_OnSlotChanged);
+ /** Returns true if SetLuaRef() has been called */
+ bool IsLuaReferenced(void) const;
-protected:
+ /** 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 callback function (Lua reference) to call when a slot is changed */
+ void SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef);
+protected:
/** Contents of the non-inventory part */
cItemGrid m_Contents;
- /** 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 plugin that has opened the window and owns the m_LuaRef */
+ cPluginLua * m_Plugin;
- /** Number of players that are currently using the window.
- Used to manager the m_LuaRef lifetime. */
- std::atomic<int> m_PlayerCount;
+ /** The Lua object reference, used for keeping the object alive as long as any player has the window open */
+ int m_LuaRef;
- /** 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 the window is closing for any player */
+ int m_OnClosingFnRef;
+ /** 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 f041ef524..523244ed2 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -992,13 +992,7 @@ static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager,
}
// Retrieve and check the hook type
- int HookType;
- if (!S.GetStackValue(a_ParamIdx, HookType))
- {
- LOGWARNING("cPluginManager.AddHook(): Cannot read the hook type.");
- S.LogStackTrace();
- return 0;
- }
+ int HookType = static_cast<int>(tolua_tonumber(S, a_ParamIdx, -1));
if (!a_PluginManager->IsValidHookType(HookType))
{
LOGWARNING("cPluginManager.AddHook(): Invalid HOOK_TYPE parameter: %d", HookType);
@@ -1007,14 +1001,7 @@ static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager,
}
// Add the hook to the plugin
- auto callback = std::make_shared<cLuaState::cCallback>();
- if (!S.GetStackValue(a_ParamIdx + 1, callback))
- {
- LOGWARNING("cPluginManager.AddHook(): Cannot read the callback parameter");
- S.LogStackTrace();
- return 0;
- }
- if (!Plugin->AddHookCallback(HookType, callback))
+ if (!Plugin->AddHookRef(HookType, a_ParamIdx + 1))
{
LOGWARNING("cPluginManager.AddHook(): Cannot add hook %d, unknown error.", HookType);
S.LogStackTrace();
@@ -1071,11 +1058,10 @@ static int tolua_cPluginManager_AddHook_DefFn(cPluginManager * a_PluginManager,
}
// Retrieve the function to call and add it to the plugin:
- auto callback = std::make_shared<cLuaState::cCallback>();
- lua_getglobal(S, FnName);
- bool res = S.GetStackValue(-1, callback);
- lua_pop(S, 1);
- if (!res || !callback->IsValid())
+ lua_pushstring(S, FnName);
+ bool res = Plugin->AddHookRef(HookType, 1);
+ lua_pop(S, 1); // Pop the function off the stack
+ if (!res)
{
LOGWARNING("cPluginManager.AddHook(): Function %s not found. Hook not added.", FnName);
S.LogStackTrace();
@@ -1599,6 +1585,55 @@ 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
@@ -1629,25 +1664,36 @@ static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S)
template <
class OBJTYPE,
- void (OBJTYPE::*SetCallback)(cLuaState::cCallbackPtr a_CallbackFn)
+ void (OBJTYPE::*SetCallback)(cPluginLua * a_Plugin, int a_FnRef)
>
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:
- cLuaState L(tolua_S);
- OBJTYPE * self;
- cLuaState::cCallbackPtr callback;
- if (!L.GetStackValues(1, self, callback))
+ OBJTYPE * self = reinterpret_cast<OBJTYPE *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (self == nullptr)
{
- LOGWARNING("%s: Cannot get parameters", __FUNCTION__);
- L.LogStackTrace();
+ 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)
+ {
+ LOGERROR("%s: Cannot create a function reference. Callback not set.", __FUNCTION__);
return 0;
}
// Set the callback
- (self->*SetCallback)(callback);
+ (self->*SetCallback)(Plugin, FnRef);
return 0;
}
@@ -1655,71 +1701,47 @@ static int tolua_SetObjectCallback(lua_State * tolua_S)
-// Callback class used for the WebTab:
-class cWebTabCallback:
- public cWebAdmin::cWebTabCallback
+static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S)
{
-public:
- /** The Lua callback to call to generate the page contents. */
- cLuaState::cCallback m_Callback;
+ cLuaState LuaState(tolua_S);
+ cPluginLua * self = nullptr;
- virtual bool Call(
- const HTTPRequest & a_Request,
- const AString & a_UrlPath,
- AString & a_Content,
- AString & a_ContentType
- ) override
+ if (!LuaState.GetStackValue(1, self))
{
- AString content, contentType;
- return m_Callback.Call(&a_Request, a_UrlPath, cLuaState::Return, a_Content, a_ContentType);
+ LOGWARNING("cPluginLua:AddWebTab: invalid self as first argument");
+ return 0;
}
-};
-
-
-
+ tolua_Error tolua_err;
+ tolua_err.array = 0;
+ tolua_err.index = 3;
+ tolua_err.type = "function";
-static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S)
-{
- // OBSOLETE, use cWebAdmin:AddWebTab() instead!
- // Function signature:
- // cPluginLua:AddWebTab(Title, CallbackFn, [UrlPath])
-
- // TODO: Warn about obsolete API usage
- // Only implement after merging the new API change and letting some time for changes in the plugins
+ std::string Title;
+ int Reference = LUA_REFNIL;
- // Check params:
- cLuaState LuaState(tolua_S);
- cPluginLua * self = cManualBindings::GetLuaPlugin(tolua_S);
- if (self == nullptr)
+ if (LuaState.CheckParamString(2) && LuaState.CheckParamFunction(3))
{
- return 0;
+ Reference = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
+ LuaState.GetStackValue(2, Title);
}
- if (
- !LuaState.CheckParamString(2) ||
- !LuaState.CheckParamFunction(3) ||
- // Optional string as param 4
- !LuaState.CheckParamEnd(5)
- )
+ else
{
- return 0;
+ return cManualBindings::tolua_do_error(tolua_S, "#ferror calling function '#funcname#'", &tolua_err);
}
- // Read the params:
- AString title, urlPath;
- auto callback = std::make_shared<cWebTabCallback>();
- if (!LuaState.GetStackValues(2, title, callback->m_Callback))
+ if (Reference != LUA_REFNIL)
{
- LOGWARNING("cPlugin:AddWebTab(): Cannot read required parameters");
- return 0;
+ if (!self->AddWebTab(Title.c_str(), tolua_S, Reference))
+ {
+ luaL_unref(tolua_S, LUA_REGISTRYINDEX, Reference);
+ }
}
- if (!LuaState.GetStackValue(4, urlPath))
+ else
{
- urlPath = cWebAdmin::GetURLEncodedString(title);
+ LOGWARNING("cPluginLua:AddWebTab: invalid function reference in 2nd argument (Title: \"%s\")", Title.c_str());
}
- cRoot::Get()->GetWebAdmin()->AddWebTab(title, urlPath, self->GetName(), callback);
-
return 0;
}
@@ -2084,68 +2106,22 @@ static int tolua_cUrlParser_ParseAuthorityPart(lua_State * a_LuaState)
-static int tolua_cWebAdmin_AddWebTab(lua_State * tolua_S)
+static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S)
{
- // Function signatures:
- // cWebAdmin:AddWebTab(Title, UrlPath, CallbackFn)
+ cWebAdmin * self = reinterpret_cast<cWebAdmin *>(tolua_tousertype(tolua_S, 1, nullptr));
- // 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;
- }
+ const cWebAdmin::PluginList & AllPlugins = self->GetPlugins();
- // 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)
-{
- // Function signature:
- // cWebAdmin:GetAllWebTabs() -> { {"PluginName", "UrlPath", "Title"}, {"PluginName", "UrlPath", "Title"}, ...}
-
- // Don't care about params at all
-
- auto webTabs = cRoot::Get()->GetWebAdmin()->GetAllWebTabs();
- lua_createtable(tolua_S, static_cast<int>(webTabs.size()), 0);
+ lua_createtable(tolua_S, static_cast<int>(AllPlugins.size()), 0);
int newTable = lua_gettop(tolua_S);
int index = 1;
- 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");
+ 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");
lua_rawseti(tolua_S, newTable, index);
+ ++iter;
++index;
}
return 1;
@@ -2155,42 +2131,14 @@ static int tolua_cWebAdmin_GetAllWebTabs(lua_State * tolua_S)
-/** Binding for cWebAdmin::GetBaseURL.
-Manual code required because ToLua generates an extra return value */
-static int tolua_cWebAdmin_GetBaseURL(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::GetBaseURL(Input));
- return 1;
-}
-
-
-
-
-
-/** Binding for cWebAdmin::GetContentTypeFromFileExt.
+/** Binding for cWebAdmin::GetHTMLEscapedString.
Manual code required because ToLua generates an extra return value */
-static int tolua_cWebAdmin_GetContentTypeFromFileExt(lua_State * tolua_S)
+static int tolua_AllToLua_cWebAdmin_GetHTMLEscapedString(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.CheckParamUserTable(1, "cWebAdmin") ||
!S.CheckParamString(2) ||
!S.CheckParamEnd(3)
)
@@ -2203,7 +2151,7 @@ static int tolua_cWebAdmin_GetContentTypeFromFileExt(lua_State * tolua_S)
S.GetStackValue(2, Input);
// Convert and return:
- S.Push(cWebAdmin::GetContentTypeFromFileExt(Input));
+ S.Push(cWebAdmin::GetHTMLEscapedString(Input));
return 1;
}
@@ -2211,14 +2159,14 @@ static int tolua_cWebAdmin_GetContentTypeFromFileExt(lua_State * tolua_S)
-/** Binding for cWebAdmin::GetHTMLEscapedString.
+/** Binding for cWebAdmin::GetURLEncodedString.
Manual code required because ToLua generates an extra return value */
-static int tolua_cWebAdmin_GetHTMLEscapedString(lua_State * tolua_S)
+static int tolua_AllToLua_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.CheckParamUserTable(1, "cWebAdmin") ||
!S.CheckParamString(2) ||
!S.CheckParamEnd(3)
)
@@ -2231,64 +2179,7 @@ static int tolua_cWebAdmin_GetHTMLEscapedString(lua_State * tolua_S)
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");
+ S.Push(cWebAdmin::GetURLEncodedString(Input));
return 1;
}
@@ -2296,27 +2187,20 @@ static int tolua_cWebAdmin_GetPage(lua_State * tolua_S)
-/** Binding for cWebAdmin::GetURLEncodedString.
-Manual code required because ToLua generates an extra return value */
-static int tolua_cWebAdmin_GetURLEncodedString(lua_State * tolua_S)
+static int tolua_cWebPlugin_GetTabNames(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)
- )
+ // 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)
{
- return 0;
+ 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;
}
-
- // Get the parameters:
- AString Input;
- S.GetStackValue(2, Input);
-
- // Convert and return:
- S.Push(cWebAdmin::GetURLEncodedString(Input));
return 1;
}
@@ -2739,79 +2623,6 @@ 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);
@@ -3655,9 +3466,6 @@ 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);
@@ -3678,6 +3486,7 @@ 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);
@@ -3741,13 +3550,13 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cWebAdmin");
- 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_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_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "HTTPRequest");
diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp
index 3faf038aa..00d2169d8 100644
--- a/src/Bindings/ManualBindings_World.cpp
+++ b/src/Bindings/ManualBindings_World.cpp
@@ -466,41 +466,67 @@ 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)
{
- // Function signature:
- // World:QueueTask(Callback)
+ // Binding for cWorld::QueueTask
+ // Params: function
- // Retrieve the args:
- cLuaState L(tolua_S);
- if (
- !L.CheckParamUserType(1, "cWorld") ||
- !L.CheckParamNumber (2) ||
- !L.CheckParamFunction(3)
- )
+ // 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;
}
- cWorld * World;
- auto Task = std::make_shared<cLuaState::cCallback>();
- if (!L.GetStackValues(1, World, Task))
+
+ // Retrieve the args:
+ cWorld * self = reinterpret_cast<cWorld *>(tolua_tousertype(tolua_S, 1, nullptr));
+ if (self == nullptr)
{
- return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Cannot read parameters");
+ return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance");
}
- if (World == nullptr)
+ if (!lua_isfunction(tolua_S, 2))
{
- 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#': Expected a function for parameter #1");
}
- if (!Task->IsValid())
+
+ // Create a reference to the function:
+ int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
+ if (FnRef == LUA_REFNIL)
{
- return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not store the callback parameter");
+ return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1");
}
- World->QueueTask([Task](cWorld & a_World)
- {
- Task->Call(&a_World);
- }
- );
+ auto ResettableTask = std::make_shared<cLuaWorldTask>(*Plugin, FnRef);
+ Plugin->AddResettable(ResettableTask);
+ self->QueueTask(std::bind(&cLuaWorldTask::Run, ResettableTask, std::placeholders::_1));
return 0;
}
@@ -550,8 +576,16 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S)
static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
{
- // Function signature:
- // World:ScheduleTask(NumTicks, Callback)
+ // 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;
+ }
// Retrieve the args:
cLuaState L(tolua_S);
@@ -563,27 +597,22 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
{
return 0;
}
- 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");
- }
+ cWorld * World = reinterpret_cast<cWorld *>(tolua_tousertype(tolua_S, 1, nullptr));
if (World == nullptr)
{
return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance");
}
- if (!Task->IsValid())
+
+ // Create a reference to the function:
+ int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
+ if (FnRef == LUA_REFNIL)
{
- return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not store the callback parameter");
+ return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1");
}
- World->ScheduleTask(NumTicks, [Task](cWorld & a_World)
- {
- Task->Call(&a_World);
- }
- );
+ 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));
return 0;
}
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index fd3e8bc69..a266e6223 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -15,8 +15,6 @@
#include "../CommandOutput.h"
#include "PluginManager.h"
#include "../Item.h"
-#include "../Root.h"
-#include "../WebAdmin.h"
extern "C"
{
@@ -60,6 +58,7 @@ void cPluginLua::Close(void)
// If already closed, bail out:
if (!m_LuaState.IsValid())
{
+ ASSERT(m_Resettables.empty());
ASSERT(m_HookMap.empty());
return;
}
@@ -67,9 +66,28 @@ void cPluginLua::Close(void)
// Remove the command bindings and web tabs:
ClearCommands();
ClearConsoleCommands();
- ClearWebTabs();
+ 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)
// 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:
@@ -187,7 +205,7 @@ bool cPluginLua::Load(void)
void cPluginLua::Unload(void)
{
- ClearWebTabs();
+ ClearTabs();
super::Unload();
Close();
}
@@ -212,7 +230,16 @@ void cPluginLua::OnDisable(void)
void cPluginLua::Tick(float a_Dt)
{
- CallSimpleHooks(cPluginManager::HOOK_TICK, 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);
+ }
}
@@ -221,7 +248,22 @@ void cPluginLua::Tick(float a_Dt)
bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
{
- return CallSimpleHooks(cPluginManager::HOOK_BLOCK_SPREAD, &a_World, a_BlockX, a_BlockY, a_BlockZ, 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;
}
@@ -230,7 +272,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_BLOCK_TO_PICKUPS, &a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &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;
}
@@ -239,7 +296,22 @@ bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_Bl
bool cPluginLua::OnBrewingCompleted(cWorld & a_World, cBrewingstandEntity & a_Brewingstand)
{
- return CallSimpleHooks(cPluginManager::HOOK_BREWING_COMPLETED, &a_World, &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;
}
@@ -248,7 +320,22 @@ bool cPluginLua::OnBrewingCompleted(cWorld & a_World, cBrewingstandEntity & a_Br
bool cPluginLua::OnBrewingCompleting(cWorld & a_World, cBrewingstandEntity & a_Brewingstand)
{
- return CallSimpleHooks(cPluginManager::HOOK_BREWING_COMPLETING, &a_World, &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;
}
@@ -263,10 +350,10 @@ bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
return false;
}
bool res = false;
- auto & hooks = m_HookMap[cPluginManager::HOOK_CHAT];
- for (auto hook: hooks)
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHAT];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
- hook->Call(&a_Player, a_Message, cLuaState::Return, res, a_Message);
+ m_LuaState.Call(static_cast<int>(**itr), &a_Player, a_Message, cLuaState::Return, res, a_Message);
if (res)
{
return true;
@@ -281,7 +368,22 @@ bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
- return CallSimpleHooks(cPluginManager::HOOK_CHUNK_AVAILABLE, &a_World, a_ChunkX, 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;
}
@@ -290,7 +392,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_CHUNK_GENERATED, &a_World, a_ChunkX, a_ChunkZ, 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;
}
@@ -299,7 +416,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_CHUNK_GENERATING, &a_World, a_ChunkX, a_ChunkZ, 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;
}
@@ -308,7 +440,22 @@ bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ,
bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
- return CallSimpleHooks(cPluginManager::HOOK_CHUNK_UNLOADED, &a_World, a_ChunkX, 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;
}
@@ -317,7 +464,22 @@ bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
{
- return CallSimpleHooks(cPluginManager::HOOK_CHUNK_UNLOADING, &a_World, a_ChunkX, 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;
}
@@ -326,7 +488,22 @@ bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ)
bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup)
{
- return CallSimpleHooks(cPluginManager::HOOK_COLLECTING_PICKUP, &a_Player, &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;
}
@@ -335,7 +512,22 @@ bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup)
bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
- return CallSimpleHooks(cPluginManager::HOOK_CRAFTING_NO_RECIPE, &a_Player, &a_Grid, &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;
}
@@ -344,7 +536,22 @@ bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid,
bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason)
{
- return CallSimpleHooks(cPluginManager::HOOK_DISCONNECT, &a_Client, 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;
}
@@ -353,7 +560,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_ENTITY_ADD_EFFECT, &a_Entity, a_EffectType, a_EffectDurationTicks, a_EffectIntensity, 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;
}
@@ -362,7 +584,22 @@ bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_E
bool cPluginLua::OnEntityChangingWorld(cEntity & a_Entity, cWorld & a_World)
{
- return CallSimpleHooks(cPluginManager::HOOK_ENTITY_CHANGING_WORLD, &a_Entity, &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;
}
@@ -371,7 +608,22 @@ bool cPluginLua::OnEntityChangingWorld(cEntity & a_Entity, cWorld & a_World)
bool cPluginLua::OnEntityChangedWorld(cEntity & a_Entity, cWorld & a_World)
{
- return CallSimpleHooks(cPluginManager::HOOK_ENTITY_CHANGED_WORLD, &a_Entity, &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;
}
@@ -386,10 +638,10 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp
return false;
}
bool res = false;
- auto & hooks = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND];
- for (auto & hook: hooks)
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
- hook->Call(a_Player, a_Split, a_EntireCommand, cLuaState::Return, res, a_Result);
+ m_LuaState.Call(static_cast<int>(**itr), a_Player, a_Split, a_EntireCommand, cLuaState::Return, res, a_Result);
if (res)
{
return true;
@@ -410,20 +662,20 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can
return false;
}
bool res = false;
- auto & hooks = m_HookMap[cPluginManager::HOOK_EXPLODED];
- for (auto & hook: hooks)
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODED];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
switch (a_Source)
{
- 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 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 esMax:
{
ASSERT(!"Invalid explosion source");
@@ -450,20 +702,20 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool &
return false;
}
bool res = false;
- auto & hooks = m_HookMap[cPluginManager::HOOK_EXPLODING];
- for (auto & hook: hooks)
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
switch (a_Source)
{
- 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 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 esMax:
{
ASSERT(!"Invalid explosion source");
@@ -484,7 +736,22 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool &
bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Username)
{
- return CallSimpleHooks(cPluginManager::HOOK_HANDSHAKE, &a_Client, 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;
}
@@ -493,7 +760,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_HOPPER_PULLING_ITEM, &a_World, &a_Hopper, a_DstSlotNum, &a_SrcEntity, 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;
}
@@ -502,7 +784,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_HOPPER_PUSHING_ITEM, &a_World, &a_Hopper, a_SrcSlotNum, &a_DstEntity, 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;
}
@@ -517,10 +814,10 @@ bool cPluginLua::OnKilled(cEntity & a_Victim, TakeDamageInfo & a_TDI, AString &
return false;
}
bool res = false;
- auto & hooks = m_HookMap[cPluginManager::HOOK_KILLED];
- for (auto & hook: hooks)
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_KILLED];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
- hook->Call(&a_Victim, &a_TDI, a_DeathMessage, cLuaState::Return, res, a_DeathMessage);
+ m_LuaState.Call(static_cast<int>(**itr), &a_Victim, &a_TDI, a_DeathMessage, cLuaState::Return, res, a_DeathMessage);
if (res)
{
return true;
@@ -535,7 +832,22 @@ bool cPluginLua::OnKilled(cEntity & a_Victim, TakeDamageInfo & a_TDI, AString &
bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI)
{
- return CallSimpleHooks(cPluginManager::HOOK_KILLING, &a_Victim, a_Killer, &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;
}
@@ -544,7 +856,22 @@ bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInf
bool cPluginLua::OnLogin(cClientHandle & a_Client, UInt32 a_ProtocolVersion, const AString & a_Username)
{
- return CallSimpleHooks(cPluginManager::HOOK_LOGIN, &a_Client, a_ProtocolVersion, 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;
}
@@ -553,7 +880,22 @@ bool cPluginLua::OnLogin(cClientHandle & a_Client, UInt32 a_ProtocolVersion, con
bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_ANIMATION, &a_Player, 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;
}
@@ -562,7 +904,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_BREAKING_BLOCK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, 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;
}
@@ -571,7 +928,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_BROKEN_BLOCK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, 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;
}
@@ -580,7 +952,22 @@ bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_Blo
bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_DESTROYED, &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;
}
@@ -589,7 +976,22 @@ bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player)
bool cPluginLua::OnPlayerEating(cPlayer & a_Player)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_EATING, &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;
}
@@ -598,7 +1000,22 @@ bool cPluginLua::OnPlayerEating(cPlayer & a_Player)
bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_FOOD_LEVEL_CHANGE, &a_Player, 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;
}
@@ -607,7 +1024,22 @@ bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel)
bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_FISHED, &a_Player, 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;
}
@@ -616,7 +1048,22 @@ bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_FISHING, &a_Player, &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;
}
@@ -625,7 +1072,22 @@ bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward)
bool cPluginLua::OnPlayerJoined(cPlayer & a_Player)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_JOINED, &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;
}
@@ -634,7 +1096,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_LEFT_CLICK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, 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;
}
@@ -643,7 +1120,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_MOVING, &a_Player, a_OldPosition, 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;
}
@@ -652,7 +1144,22 @@ bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPositi
bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition)
{
- return CallSimpleHooks(cPluginManager::HOOK_ENTITY_TELEPORT, &a_Entity, a_OldPosition, 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;
}
@@ -661,11 +1168,27 @@ bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosi
bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
- 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
- );
+ 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;
}
@@ -674,11 +1197,27 @@ bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_Blo
bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
- 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
- );
+ 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;
}
@@ -687,7 +1226,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_RIGHT_CLICK, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, 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;
}
@@ -696,7 +1250,22 @@ bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_Bloc
bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY, &a_Player, &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;
}
@@ -705,7 +1274,22 @@ bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Ent
bool cPluginLua::OnPlayerShooting(cPlayer & a_Player)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_SHOOTING, &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;
}
@@ -714,7 +1298,22 @@ bool cPluginLua::OnPlayerShooting(cPlayer & a_Player)
bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_SPAWNED, &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;
}
@@ -723,7 +1322,22 @@ bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player)
bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_TOSSING_ITEM, &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;
}
@@ -732,7 +1346,22 @@ 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)
{
- 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);
+ 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;
}
@@ -741,7 +1370,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_USED_ITEM, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, 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;
}
@@ -750,7 +1394,22 @@ 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)
{
- 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);
+ 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;
}
@@ -759,7 +1418,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLAYER_USING_ITEM, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, 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;
}
@@ -768,7 +1442,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_PLUGIN_MESSAGE, &a_Client, a_Channel, 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;
}
@@ -783,11 +1472,11 @@ bool cPluginLua::OnPluginsLoaded(void)
return false;
}
bool res = false;
- auto & hooks = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED];
- for (auto & hook: hooks)
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
bool ret = false;
- hook->Call(cLuaState::Return, ret);
+ m_LuaState.Call(static_cast<int>(**itr), cLuaState::Return, ret);
res = res || ret;
}
return res;
@@ -799,7 +1488,22 @@ bool cPluginLua::OnPluginsLoaded(void)
bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
- return CallSimpleHooks(cPluginManager::HOOK_POST_CRAFTING, &a_Player, &a_Grid, &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;
}
@@ -808,7 +1512,22 @@ bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCra
bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe)
{
- return CallSimpleHooks(cPluginManager::HOOK_PRE_CRAFTING, &a_Player, &a_Grid, &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;
}
@@ -817,7 +1536,22 @@ 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)
{
- return CallSimpleHooks(cPluginManager::HOOK_PROJECTILE_HIT_BLOCK, &a_Projectile, a_BlockX, a_BlockY, a_BlockZ, a_Face, 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;
}
@@ -826,7 +1560,22 @@ bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_Bl
bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
{
- return CallSimpleHooks(cPluginManager::HOOK_PROJECTILE_HIT_ENTITY, &a_Projectile, &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;
}
@@ -841,10 +1590,10 @@ bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_Server
return false;
}
bool res = false;
- auto & hooks = m_HookMap[cPluginManager::HOOK_SERVER_PING];
- for (auto & hook: hooks)
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
- hook->Call(&a_ClientHandle, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon, cLuaState::Return, res, a_ServerDescription, a_OnlinePlayersCount, a_MaxPlayersCount, a_Favicon);
+ 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);
if (res)
{
return true;
@@ -859,7 +1608,22 @@ bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_Server
bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
- return CallSimpleHooks(cPluginManager::HOOK_SPAWNED_ENTITY, &a_World, &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;
}
@@ -868,7 +1632,22 @@ bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster)
{
- return CallSimpleHooks(cPluginManager::HOOK_SPAWNED_MONSTER, &a_World, &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;
}
@@ -877,7 +1656,22 @@ bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster)
bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity)
{
- return CallSimpleHooks(cPluginManager::HOOK_SPAWNING_ENTITY, &a_World, &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;
}
@@ -886,7 +1680,22 @@ bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity)
bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster)
{
- return CallSimpleHooks(cPluginManager::HOOK_SPAWNING_MONSTER, &a_World, &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;
}
@@ -895,7 +1704,22 @@ bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster)
bool cPluginLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI)
{
- return CallSimpleHooks(cPluginManager::HOOK_TAKE_DAMAGE, &a_Receiver, &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;
}
@@ -909,7 +1733,22 @@ bool cPluginLua::OnUpdatedSign(
cPlayer * a_Player
)
{
- return CallSimpleHooks(cPluginManager::HOOK_UPDATED_SIGN, &a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, 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;
}
@@ -929,10 +1768,10 @@ bool cPluginLua::OnUpdatingSign(
return false;
}
bool res = false;
- auto & hooks = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN];
- for (auto & hook: hooks)
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
- 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);
+ 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);
if (res)
{
return true;
@@ -947,7 +1786,22 @@ bool cPluginLua::OnUpdatingSign(
bool cPluginLua::OnWeatherChanged(cWorld & a_World)
{
- return CallSimpleHooks(cPluginManager::HOOK_WEATHER_CHANGED, &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;
}
@@ -962,10 +1816,10 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
return false;
}
bool res = false;
- auto & hooks = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING];
- for (auto & hook: hooks)
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
- hook->Call(&a_World, a_NewWeather, cLuaState::Return, res, a_NewWeather);
+ m_LuaState.Call(static_cast<int>(**itr), &a_World, a_NewWeather, cLuaState::Return, res, a_NewWeather);
if (res)
{
return true;
@@ -980,7 +1834,17 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
bool cPluginLua::OnWorldStarted(cWorld & a_World)
{
- return CallSimpleHooks(cPluginManager::HOOK_WORLD_STARTED, &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;
}
@@ -989,7 +1853,17 @@ bool cPluginLua::OnWorldStarted(cWorld & a_World)
bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
{
- return CallSimpleHooks(cPluginManager::HOOK_WORLD_TICK, &a_World, a_Dt, 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;
}
@@ -1185,11 +2059,22 @@ const char * cPluginLua::GetHookFnName(int a_HookType)
-bool cPluginLua::AddHookCallback(int a_HookType, cLuaState::cCallbackPtr a_Callback)
+bool cPluginLua::AddHookRef(int a_HookType, int a_FnRefIdx)
{
ASSERT(m_CriticalSection.IsLockedByCurrentThread()); // It probably has to be, how else would we have a LuaState?
- m_HookMap[a_HookType].push_back(a_Callback);
+ // 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);
return true;
}
@@ -1231,6 +2116,61 @@ 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)
+{
+ cCSLock Lock(m_CriticalSection);
+ if (a_LuaState != m_LuaState)
+ {
+ LOGERROR("Only allowed to add a tab to a WebPlugin of your own Plugin!");
+ return false;
+ }
+ 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());
@@ -1287,13 +2227,22 @@ void cPluginLua::CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int
-void cPluginLua::ClearWebTabs(void)
+////////////////////////////////////////////////////////////////////////////////
+// cPluginLua::cResettable:
+
+cPluginLua::cResettable::cResettable(cPluginLua & a_Plugin):
+ m_Plugin(&a_Plugin)
{
- auto webAdmin = cRoot::Get()->GetWebAdmin();
- if (webAdmin != nullptr) // can be nullptr when shutting down the server
- {
- webAdmin->RemoveAllPluginWebTabs(m_Name);
- }
+}
+
+
+
+
+
+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 e53fbaaa8..db6612671 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -10,6 +10,7 @@
#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
@@ -28,7 +29,8 @@ class cWindow;
// tolua_begin
class cPluginLua :
- public cPlugin
+ public cPlugin,
+ public cWebPlugin
{
typedef cPlugin super;
@@ -62,6 +64,36 @@ public:
+ /** 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();
@@ -149,6 +181,14 @@ public:
/** 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);
@@ -171,9 +211,11 @@ public:
/** 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 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);
+ /** 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);
/** 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.
@@ -193,23 +235,29 @@ public:
return m_LuaState.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::cCallbackPtr> cLuaCallbacks;
+ typedef std::vector<cLuaState::cRef *> cLuaRefs;
/** Maps hook types into arrays of Lua function references to call for each hook type */
- typedef std::map<int, cLuaCallbacks> cHookMap;
+ typedef std::map<int, cLuaRefs> cHookMap;
- /** The mutex protecting m_LuaState against multithreaded use. */
+ /** 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;
@@ -222,30 +270,6 @@ protected:
/** 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)
- {
- cCSLock lock(m_CriticalSection);
- 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 203450505..5b3ef7803 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -1965,23 +1965,6 @@ 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 a97582fbe..f3f0b6d0b 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -332,9 +332,6 @@ 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
diff --git a/src/Bindings/WebPlugin.cpp b/src/Bindings/WebPlugin.cpp
new file mode 100644
index 000000000..1eca7de93
--- /dev/null
+++ b/src/Bindings/WebPlugin.cpp
@@ -0,0 +1,152 @@
+
+#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
new file mode 100644
index 000000000..6dc8db801
--- /dev/null
+++ b/src/Bindings/WebPlugin.h
@@ -0,0 +1,80 @@
+
+#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 bca9c5547..6d092eeb3 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -225,10 +225,10 @@ public:
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
const cWindow * GetWindow(void) const { return m_CurrentWindow; }
- // tolua_begin
-
/** Opens the specified window; closes the current one first using CloseWindow() */
- void OpenWindow(cWindow * a_Window);
+ void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp
+
+ // tolua_begin
/** 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/UI/Window.cpp b/src/UI/Window.cpp
index 4582d6cf4..5a2e55feb 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 is holding an item while closing their window, dropping it as a pickup...");
+ LOGD("Player holds item! Dropping it...");
a_Player.TossHeldItem(a_Player.GetDraggingItem().m_ItemCount);
}
diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp
index 5c08deb0d..e43d749dd 100644
--- a/src/WebAdmin.cpp
+++ b/src/WebAdmin.cpp
@@ -2,6 +2,10 @@
#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"
@@ -83,9 +87,9 @@ public:
// cWebAdmin:
cWebAdmin::cWebAdmin(void) :
- m_TemplateScript("<webadmin_template>"),
m_IsInitialized(false),
- m_IsRunning(false)
+ m_IsRunning(false),
+ m_TemplateScript("<webadmin_template>")
{
}
@@ -102,9 +106,40 @@ 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 (!LoadIniFile())
+ 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))
{
// WebAdmin is disabled, bail out faking a success
return true;
@@ -112,7 +147,31 @@ bool cWebAdmin::Init(void)
LOGD("Initialising WebAdmin...");
- Reload();
+ // 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>";
+ }
// Read the ports to be used:
// Note that historically the ports were stored in the "Port" and "PortsIPv6" values
@@ -165,7 +224,7 @@ void cWebAdmin::Stop(void)
-bool cWebAdmin::LoadLoginPage(void)
+bool cWebAdmin::LoadLoginTemplate(void)
{
cFile File(FILE_IO_PREFIX "webadmin/login_template.html", cFile::fmRead);
if (!File.IsOpen())
@@ -179,8 +238,7 @@ bool cWebAdmin::LoadLoginPage(void)
return false;
}
- cCSLock Lock(m_CS);
- m_LoginPage = TemplateContent;
+ m_LoginTemplate = TemplateContent;
return true;
}
@@ -188,89 +246,6 @@ bool cWebAdmin::LoadLoginPage(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())
@@ -280,20 +255,17 @@ 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))
{
- 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;
- }
+ 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.empty() && (BareURL[1] != '~'));
+ bool ShouldWrapInTemplate = ((BareURL.length() > 1) && (BareURL[1] != '~'));
// Retrieve the request data:
auto Data = std::static_pointer_cast<cWebadminRequestData>(a_Request.GetUserData());
@@ -340,7 +312,6 @@ 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;
@@ -354,12 +325,59 @@ void cWebAdmin::HandleWebadminRequest(cHTTPServerConnection & a_Connection, cHTT
return;
}
- // 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());
+ 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());
a_Connection.FinishResponse();
}
@@ -374,7 +392,7 @@ void cWebAdmin::HandleRootRequest(cHTTPServerConnection & a_Connection, cHTTPInc
cHTTPOutgoingResponse Resp;
Resp.SetContentType("text/html");
a_Connection.Send(Resp);
- a_Connection.Send(m_LoginPage);
+ a_Connection.Send(m_LoginTemplate);
a_Connection.FinishResponse();
}
@@ -388,7 +406,7 @@ void cWebAdmin::HandleFileRequest(cHTTPServerConnection & a_Connection, cHTTPInc
std::replace(FileURL.begin(), FileURL.end(), '\\', '/');
// Remove all leading backslashes:
- if (!FileURL.empty() && (FileURL[0] == '/'))
+ if (FileURL[0] == '/')
{
size_t FirstCharToRead = FileURL.find_first_not_of('/');
if (FirstCharToRead != AString::npos)
@@ -400,9 +418,8 @@ void cWebAdmin::HandleFileRequest(cHTTPServerConnection & a_Connection, cHTTPInc
// Remove all "../" strings:
ReplaceString(FileURL, "../", "");
- // Read the file contents and guess its mime-type, based on the extension:
+ bool LoadedSuccessfull = false;
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))
{
@@ -410,17 +427,18 @@ void cWebAdmin::HandleFileRequest(cHTTPServerConnection & a_Connection, cHTTPInc
AString FileContent;
if (File.IsOpen() && (File.ReadRestOfFile(FileContent) != -1))
{
- std::swap(Content, FileContent);
- size_t LastPointPosition = Path.find_last_of('.');
- if (LastPointPosition != AString::npos)
- {
- ContentType = GetContentTypeFromFileExt(Path.substr(LastPointPosition + 1));
- }
+ LoadedSuccessfull = true;
+ Content = FileContent;
}
}
- if (ContentType.empty())
+
+ // 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()))
{
- ContentType = "application/unknown";
+ AString FileExtension = Path.substr(LastPointPosition + 1);
+ ContentType = GetContentTypeFromFileExt(FileExtension);
}
// Send the response:
@@ -438,36 +456,32 @@ void cWebAdmin::HandleFileRequest(cHTTPServerConnection & a_Connection, cHTTPInc
AString cWebAdmin::GetContentTypeFromFileExt(const AString & a_FileExtension)
{
static bool IsInitialized = false;
- static AStringMap ContentTypeMap;
+ static std::map<AString, AString> 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"] = "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;
+ 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];
}
@@ -476,93 +490,86 @@ AString cWebAdmin::GetContentTypeFromFileExt(const AString & a_FileExtension)
sWebAdminPage cWebAdmin::GetPage(const HTTPRequest & a_Request)
{
- sWebAdminPage page;
- auto split = StringSplit(a_Request.Path, "/");
-
- // If no specific page was requested, return an empty object:
- if (split.size() <= 2)
- {
- return page;
- }
+ sWebAdminPage Page;
+ AStringVector Split = StringSplit(a_Request.Path, "/");
- // Find the WebTab handler responsible for the request:
- cWebTabPtr tab;
+ // Find the plugin that corresponds to the requested path
+ AString FoundPlugin;
+ if (Split.size() > 1)
{
- cCSLock Lock(m_CS);
- for (auto & wt: m_WebTabs)
+ for (PluginList::iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr)
{
- if (
- (wt->m_PluginName == split[1]) &&
- (wt->m_UrlPath == split[2])
- )
+ if ((*itr)->GetWebTitle() == Split[1])
{
- tab = wt;
+ 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;
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 page;
+ // Return the page contents
+ return Page;
}
-AString cWebAdmin::GetBaseURL(const AString & a_URL)
+AString cWebAdmin::GetDefaultPage(void)
{
- return GetBaseURL(StringSplit(a_URL, "/"));
-}
-
+ AString Content;
+ Content += "<h4>Server Name:</h4>";
+ Content += "<p>" + AString( cRoot::Get()->GetServer()->GetServerID()) + "</p>";
+ // 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>";
-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));
+ // 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;
}
-bool cWebAdmin::DelWebTab(const AString & a_UrlPath)
+AString cWebAdmin::GetBaseURL(const AString & 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;
+ return GetBaseURL(StringSplit(a_URL, "/"));
}
diff --git a/src/WebAdmin.h b/src/WebAdmin.h
index b76ca6df8..5e48f597c 100644
--- a/src/WebAdmin.h
+++ b/src/WebAdmin.h
@@ -89,14 +89,14 @@ struct HTTPTemplateRequest
+// tolua_begin
struct sWebAdminPage
{
AString Content;
AString PluginName;
- AString TabTitle;
- AString TabUrlPath;
- AString ContentType;
+ AString TabName;
};
+// tolua_end
@@ -111,49 +111,7 @@ class cWebAdmin :
public:
// tolua_end
- /** 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;
+ typedef std::list< cWebPlugin* > PluginList;
cWebAdmin(void);
@@ -162,114 +120,80 @@ public:
/** Initializes the object. Returns true if successfully initialized and ready to start */
bool Init(void);
- /** Starts the HTTP server taking care of the webadmin. Returns true if successful */
+ /** Starts the HTTP server taking care of the admin. Returns true if successful */
bool Start(void);
/** Stops the HTTP server, if it was started. */
void Stop(void);
- /** Loads the login template into m_LoginPage.
- Returns true if the loading succeeds, false if not. */
- bool LoadLoginPage(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);
- /** Returns a copy of all the registered web tabs.
- Exported to Lua in ManualBindings.cpp. */
- cWebTabPtrs GetAllWebTabs(void) { return m_WebTabs; }
+ // 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 <<
- /** Removes all WebTabs registered by the specified plugin. */
- void RemoveAllPluginWebTabs(const AString & a_PluginName);
+ // tolua_begin
- /** 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);
- // tolua_begin
+ /** Returns the contents of the default page - the list of plugins and players */
+ AString GetDefaultPage(void);
- /** 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 prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */
+ AString GetBaseURL(const AString & a_URL);
- /** Returns the list of ports on which the webadmin is configured to listen. */
+ /** Returns the list of ports used for the webadmin. */
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
- /** 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. */
+ /** Escapes text passed into it, so it can be embedded into html. */
static AString GetHTMLEscapedString(const AString & a_Input);
- /** Escapes the string for use in an URL
- Exported to Lua in ManualBindings.cpp. */
+ /** Escapes the string for use in an URL */
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 an empty string.
- Exported to Lua in ManualBindings.cpp. */
+ /** Returns the content type from the file extension. If the extension isn't in the list, the function returns "text/html" */
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 HTTP server which provides the underlying HTTP parsing, serialization and events */
- cHTTPServer m_HTTPServer;
+ /** The Lua template script to provide templates: */
+ cLuaState m_TemplateScript;
+ /** The template that provides the login site: */
+ AString m_LoginTemplate;
- /** 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);
+ /** The HTTP server which provides the underlying HTTP parsing, serialization and events */
+ cHTTPServer m_HTTPServer;
/** Handles requests coming to the "/webadmin" or "/~webadmin" URLs */
void HandleWebadminRequest(cHTTPServerConnection & a_Connection, cHTTPIncomingRequest & a_Request);