summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/ManualBindings.cpp176
-rw-r--r--source/StringUtils.cpp27
-rw-r--r--source/StringUtils.h3
-rw-r--r--source/cRoot.cpp53
-rw-r--r--source/cRoot.h5
-rw-r--r--source/cWorld.cpp36
-rw-r--r--source/cWorld.h3
7 files changed, 220 insertions, 83 deletions
diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp
index 10109c669..f25a56aa2 100644
--- a/source/ManualBindings.cpp
+++ b/source/ManualBindings.cpp
@@ -108,91 +108,93 @@ static int tolua_LOGERROR(lua_State* tolua_S)
-static int tolua_cWorld_DoWithPlayer(lua_State * tolua_S)
-{
- int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */
- if ((NumArgs != 2) && (NumArgs != 3))
- {
- LOGWARN("Error in function call 'cWorld:DoWithPlayer()': Requires 2 or 3 arguments, got %i", NumArgs );
- return 0;
- }
-
- cWorld * self = (cWorld *) tolua_tousertype(tolua_S, 1, 0);
-
- const char * PlayerName = tolua_tocppstring(tolua_S, 2, "");
- if ((PlayerName == NULL) || (PlayerName[0] == 0))
- {
- LOGWARN("Error in function call 'cWorld:DoWithPlayer()': Expected a non-empty string for parameter #1");
- return 0;
- }
- if (!lua_isfunction( tolua_S, 3))
- {
- LOGWARN("Error in function call 'cWorld:DoWithPlayer()': Expected a function for parameter #2");
- return 0;
- }
-
- /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */
- int TableRef = LUA_REFNIL;
- if (NumArgs == 3)
- {
- TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
- if (TableRef == LUA_REFNIL)
- {
- LOGWARN("Error in function call 'cWorld:DoWithPlayer()': Could not get value reference of parameter #3");
- return 0;
- }
- }
-
- /* table value is popped, and now function is on top of the stack */
- int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
- if (FuncRef == LUA_REFNIL)
- {
- LOGWARN("Error in function call 'cWorld:DoWithPlayer()': Could not get function reference of parameter #2");
- return 0;
- }
-
- class cLuaCallback : public cItemCallback<cPlayer>
- {
- public:
- cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef)
- : LuaState( a_LuaState )
- , FuncRef( a_FuncRef )
- , TableRef( a_TableRef )
- {}
-
- private:
- virtual bool Item(cPlayer * a_Item) override
- {
- lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */
- tolua_pushusertype(LuaState, a_Item, "cPlayer");
- if (TableRef != LUA_REFNIL)
- {
- lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */
- }
-
- int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0);
- report_errors(LuaState, s);
- return true;
- }
- lua_State * LuaState;
- int FuncRef;
- int TableRef;
- } Callback(tolua_S, FuncRef, TableRef);
-
- bool bRetVal = self->DoWithPlayer(PlayerName, Callback);
-
- /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */
- luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef);
- luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef);
-
- /* Push return value on stack */
- tolua_pushboolean(tolua_S, bRetVal );
- return 1;
+#define DEFINE_LUA_DOWITH(CONTAINER,ITEM,FOREACH,FNNAME) \
+static int FNNAME(lua_State * tolua_S) \
+{ \
+ int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ \
+ if ((NumArgs != 2) && (NumArgs != 3)) \
+ { \
+ LOGWARN("Error in function call '" #FOREACH "': Requires 2 or 3 arguments, got %i", NumArgs ); \
+ return 0; \
+ } \
+ \
+ CONTAINER * self = (CONTAINER *) tolua_tousertype(tolua_S, 1, 0); \
+ \
+ const char * ItemName = tolua_tocppstring(tolua_S, 2, ""); \
+ if ((ItemName == NULL) || (ItemName[0] == 0)) \
+ { \
+ LOGWARN("Error in function call '" #FOREACH "': Expected a non-empty string for parameter #1"); \
+ return 0; \
+ } \
+ if (!lua_isfunction( tolua_S, 3)) \
+ { \
+ LOGWARN("Error in function call '" #FOREACH "': Expected a function for parameter #2"); \
+ return 0; \
+ } \
+ \
+ /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ \
+ int TableRef = LUA_REFNIL; \
+ if (NumArgs == 3) \
+ { \
+ TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \
+ if (TableRef == LUA_REFNIL) \
+ { \
+ LOGWARN("Error in function call '" #FOREACH "': Could not get value reference of parameter #3"); \
+ return 0; \
+ } \
+ } \
+ \
+ /* table value is popped, and now function is on top of the stack */ \
+ int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \
+ if (FuncRef == LUA_REFNIL) \
+ { \
+ LOGWARN("Error in function call '" #FOREACH "': Could not get function reference of parameter #2"); \
+ return 0; \
+ } \
+ \
+ class cLuaCallback : public cItemCallback<ITEM> \
+ { \
+ public: \
+ cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) \
+ : LuaState( a_LuaState ) \
+ , FuncRef( a_FuncRef ) \
+ , TableRef( a_TableRef ) \
+ {} \
+ \
+ private: \
+ virtual bool Item(ITEM * a_Item) override \
+ { \
+ lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ \
+ tolua_pushusertype(LuaState, a_Item, #ITEM); \
+ if (TableRef != LUA_REFNIL) \
+ { \
+ lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ \
+ } \
+ \
+ int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); \
+ report_errors(LuaState, s); \
+ return true; \
+ } \
+ lua_State * LuaState; \
+ int FuncRef; \
+ int TableRef; \
+ } Callback(tolua_S, FuncRef, TableRef); \
+ \
+ bool bRetVal = self->FOREACH(ItemName, Callback); \
+ \
+ /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ \
+ luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); \
+ luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); \
+ \
+ /* Push return value on stack */ \
+ tolua_pushboolean(tolua_S, bRetVal ); \
+ return 1; \
}
+
#define DEFINE_LUA_FOREACHINCHUNK(CONTAINER,ITEM,FOREACH,FNNAME) \
static int FNNAME(lua_State * tolua_S) \
{ \
@@ -378,10 +380,17 @@ static int FNNAME(lua_State * tolua_S) \
+
+// Define the DoWith enumerators: (they take a string and a callback class)
+DEFINE_LUA_DOWITH(cWorld, cPlayer, DoWithPlayer, tolua_cWorld_DoWithPlayer);
+DEFINE_LUA_DOWITH(cWorld, cPlayer, FindAndDoWithPlayer, tolua_cWorld_FindAndDoWithPlayer);
+DEFINE_LUA_DOWITH(cRoot, cPlayer, FindAndDoWithPlayer, tolua_cRoot_FindAndDoWithPlayer);
+
// Define the ForEach enumerators:
DEFINE_LUA_FOREACH(cWorld, cPlayer, ForEachPlayer, tolua_cWorld_ForEachPlayer);
-DEFINE_LUA_FOREACH(cRoot, cWorld, ForEachWorld, tolua_cRoot_ForEachWorld);
DEFINE_LUA_FOREACH(cWorld, cEntity, ForEachEntity, tolua_cWorld_ForEachEntity);
+DEFINE_LUA_FOREACH(cRoot, cWorld, ForEachWorld, tolua_cRoot_ForEachWorld);
+DEFINE_LUA_FOREACH(cRoot, cPlayer, ForEachPlayer, tolua_cRoot_ForEachPlayer);
DEFINE_LUA_FOREACHINCHUNK(cWorld, cEntity, ForEachEntityInChunk, tolua_cWorld_ForEachEntityInChunk);
DEFINE_LUA_FOREACHINCHUNK(cWorld, cChestEntity, ForEachChestInChunk, tolua_cWorld_ForEachChestInChunk);
@@ -694,6 +703,8 @@ void ManualBindings::Bind( lua_State* tolua_S )
tolua_beginmodule(tolua_S, "cRoot");
tolua_function(tolua_S, "ForEachWorld", tolua_cRoot_ForEachWorld);
+ tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_cRoot_FindAndDoWithPlayer);
+ tolua_function(tolua_S, "ForEachPlayer", tolua_cRoot_ForEachPlayer);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cWorld");
@@ -702,7 +713,8 @@ void ManualBindings::Bind( lua_State* tolua_S )
tolua_function(tolua_S, "ForEachEntityInChunk", tolua_cWorld_ForEachEntityInChunk);
tolua_function(tolua_S, "ForEachChestInChunk", tolua_cWorld_ForEachChestInChunk);
tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_cWorld_ForEachFurnaceInChunk);
- tolua_function(tolua_S, "DoWithPlayer", tolua_cWorld_DoWithPlayer);
+ tolua_function(tolua_S, "DoWithPlayer", tolua_cWorld_DoWithPlayer);
+ tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_cWorld_FindAndDoWithPlayer);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cPlugin");
diff --git a/source/StringUtils.cpp b/source/StringUtils.cpp
index ccdbe687a..e3eb95a6e 100644
--- a/source/StringUtils.cpp
+++ b/source/StringUtils.cpp
@@ -172,6 +172,33 @@ int NoCaseCompare(const AString & s1, const AString & s2)
+unsigned int RateCompareString(const AString & s1, const AString & s2 )
+{
+ unsigned int MatchedLetters = 0;
+ unsigned int s1Length = s1.length();
+
+ if( s1Length > s2.length() ) return 0; // Definitely not a match
+
+ for (unsigned int i = 0; i < s1Length; i++)
+ {
+ char c1 = (char)toupper( s1[i] );
+ char c2 = (char)toupper( s2[i] );
+ if( c1 == c2 )
+ {
+ ++MatchedLetters;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return MatchedLetters;
+}
+
+
+
+
+
void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith)
{
size_t pos1 = iHayStack.find(iNeedle);
diff --git a/source/StringUtils.h b/source/StringUtils.h
index bc3c937b5..6ab95880a 100644
--- a/source/StringUtils.h
+++ b/source/StringUtils.h
@@ -42,6 +42,9 @@ extern AString & StrToUpper(AString & s);
/// Case-insensitive string comparison; returns 0 if the strings are the same
extern int NoCaseCompare(const AString & s1, const AString & s2);
+/// Case-insensitive string comparison that returns a rating of equal-ness between [0 - s1.length()]
+extern unsigned int RateCompareString(const AString & s1, const AString & s2 );
+
/// Replaces *each* occurence of iNeedle in iHayStack with iReplaceWith
extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith);
diff --git a/source/cRoot.cpp b/source/cRoot.cpp
index 5c0c08f7d..4c87210c7 100644
--- a/source/cRoot.cpp
+++ b/source/cRoot.cpp
@@ -14,6 +14,7 @@
#include "cThread.h"
#include "cFileFormatUpdater.h"
#include "cRedstone.h"
+#include "cPlayer.h"
#include "blocks/Block.h"
#include "items/Item.h"
#include "cChunk.h"
@@ -423,6 +424,58 @@ bool cRoot::ForEachPlayer(cPlayerListCallback & a_Callback)
+bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
+{
+ class cCallback : public cPlayerListCallback
+ {
+ unsigned int BestRating;
+ unsigned int NameLength;
+ const AString PlayerName;
+
+ cPlayerListCallback & m_Callback;
+ virtual bool Item (cPlayer * a_pPlayer)
+ {
+ unsigned int Rating = RateCompareString (PlayerName, a_pPlayer->GetName());
+ if (Rating > 0 && Rating >= BestRating)
+ {
+ BestMatch = a_pPlayer;
+ if( Rating > BestRating ) NumMatches = 0;
+ BestRating = Rating;
+ ++NumMatches;
+ }
+ if (Rating == NameLength) // Perfect match
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public:
+ cCallback (const AString & a_PlayerName, cPlayerListCallback & a_Callback)
+ : m_Callback( a_Callback )
+ , BestMatch( NULL )
+ , BestRating( 0 )
+ , NumMatches( 0 )
+ , NameLength( a_PlayerName.length() )
+ , PlayerName( a_PlayerName )
+ {}
+
+ cPlayer * BestMatch;
+ unsigned int NumMatches;
+ } Callback (a_PlayerName, a_Callback);
+ ForEachPlayer( Callback );
+
+ if (Callback.NumMatches == 1)
+ {
+ return a_Callback.Item (Callback.BestMatch);
+ }
+ return false;
+}
+
+
+
+
+
void cRoot::LogChunkStats(void)
{
int SumNumValid = 0;
diff --git a/source/cRoot.h b/source/cRoot.h
index b65c1d91d..e25a9805b 100644
--- a/source/cRoot.h
+++ b/source/cRoot.h
@@ -70,7 +70,10 @@ public:
void SaveAllChunks(void);
/// Calls the callback for each player in all worlds
- bool ForEachPlayer(cPlayerListCallback & a_Callback);
+ bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ /// Finds a player from a partial or complete player name and calls the callback - case-insensitive
+ bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
private:
void LoadGlobalSettings();
diff --git a/source/cWorld.cpp b/source/cWorld.cpp
index a981a24c0..f12f9f1a8 100644
--- a/source/cWorld.cpp
+++ b/source/cWorld.cpp
@@ -1614,6 +1614,42 @@ bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_
+bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
+{
+ cPlayer* BestMatch = 0;
+ unsigned int BestRating = 0;
+ unsigned int NumMatches = 0;
+ unsigned int NameLength = a_PlayerName.length();
+
+ cCSLock Lock(m_CSPlayers);
+ for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ {
+ unsigned int Rating = RateCompareString (a_PlayerName, (*itr)->GetName());
+ if (Rating > 0 && Rating >= BestRating)
+ {
+ BestMatch = *itr;
+ if( Rating > BestRating ) NumMatches = 0;
+ BestRating = Rating;
+ ++NumMatches;
+ }
+ if (Rating == NameLength) // Perfect match
+ {
+ break;
+ }
+ } // for itr - m_Players[]
+
+ if (NumMatches == 1)
+ {
+ LOG("Compared %s and %s with rating %i", a_PlayerName.c_str(), BestMatch->GetName().c_str(), BestRating );
+ return a_Callback.Item (BestMatch);
+ }
+ return false;
+}
+
+
+
+
+
// TODO: This interface is dangerous!
cPlayer * cWorld::FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit)
{
diff --git a/source/cWorld.h b/source/cWorld.h
index 5c2132050..6cac25b66 100644
--- a/source/cWorld.h
+++ b/source/cWorld.h
@@ -150,6 +150,9 @@ public:
/// Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored
bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ /// Finds a player from a partial or complete player name and calls the callback - case-insensitive
+ bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
unsigned int GetNumPlayers(); //tolua_export