diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 383f792b2..c1db27be4 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -102,6 +102,102 @@ static int tolua_LOGERROR(lua_State* tolua_S) +static int tolua_cWorld_ForEachEntityInChunk(lua_State * tolua_S) +{ + int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ + if ((NumArgs != 3) && (NumArgs != 4)) + { + LOGWARN("Error in function call 'ForEachEntityInChunk': Requires 3 or 4 arguments, got %i", NumArgs); + return 0; + } + + cWorld * self = (cWorld *) tolua_tousertype(tolua_S, 1, 0); + if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3)) + { + LOGWARN("Errorin function call 'ForEachEntityInChunk': Expected a number for parameters #1 and #2"); + return 0; + } + + int ChunkX = ((int)tolua_tonumber(tolua_S, 2, 0)); + int ChunkZ = ((int)tolua_tonumber(tolua_S, 3, 0)); + + if (!lua_isfunction( tolua_S, 4)) + { + LOGWARN("Error in function call 'ForEachEntityInChunk': Expected a function for parameter #3"); + 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 == 4) + { + TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (TableRef == LUA_REFNIL) + { + LOGWARN("Error in function call 'ForEachEntityInChunk': Could not get value reference of parameter #4"); + 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 'ForEachEntityInChunk': Could not get function reference of parameter #3"); + return 0; + } + + class cLuaPlayerCallback : public cItemCallback + { + public: + cLuaPlayerCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) + : LuaState( a_LuaState ) + , FuncRef( a_FuncRef ) + , TableRef( a_TableRef ) + {} + + private: + virtual bool Item(cEntity * a_Item) override + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ + tolua_pushusertype(LuaState, a_Item, "cEntity"); + 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); + if (report_errors(LuaState, s)) + { + return true; /* Abort enumeration */ + } + + if (lua_isboolean(LuaState, -1)) + { + return (tolua_toboolean( LuaState, -1, 0) > 0); + } + return false; /* Continue enumeration */ + } + lua_State * LuaState; + int FuncRef; + int TableRef; + } Callback(tolua_S, FuncRef, TableRef); + + bool bRetVal = self->ForEachEntityInChunk(ChunkX, ChunkZ, 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_FOREACH(CONTAINER,ITEM,FOREACH,FNNAME) \ static int FNNAME(lua_State * tolua_S) \ { \ @@ -191,14 +287,15 @@ static int FNNAME(lua_State * tolua_S) \ // 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, cPlayer, ForEachPlayer, tolua_cWorld_ForEachPlayer); +DEFINE_LUA_FOREACH(cRoot, cWorld, ForEachWorld, tolua_cRoot_ForEachWorld); +DEFINE_LUA_FOREACH(cWorld, cEntity, ForEachEntity, tolua_cWorld_ForEachEntity); -static int tolua_cPlugin_GetCommands(lua_State* tolua_S) +static int tolua_cPlugin_GetCommands(lua_State * tolua_S) { cPlugin* self = (cPlugin*) tolua_tousertype(tolua_S,1,0); @@ -482,32 +579,39 @@ static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S) void ManualBindings::Bind( lua_State* tolua_S ) { tolua_beginmodule(tolua_S,NULL); - tolua_function(tolua_S,"StringSplit",tolua_StringSplit); - tolua_function(tolua_S,"LOG",tolua_LOG); - tolua_function(tolua_S,"LOGINFO",tolua_LOGINFO); - tolua_function(tolua_S,"LOGWARN",tolua_LOGWARN); - tolua_function(tolua_S,"LOGERROR",tolua_LOGERROR); - tolua_function(tolua_S,"Log",tolua_LOG); // Deprecated + tolua_function(tolua_S, "StringSplit", tolua_StringSplit); + tolua_function(tolua_S, "LOG", tolua_LOG); + tolua_function(tolua_S, "LOGINFO", tolua_LOGINFO); + tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN); + tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); + tolua_function(tolua_S, "Log", tolua_LOG); // Deprecated - tolua_beginmodule(tolua_S,"cRoot"); - tolua_function(tolua_S,"ForEachWorld",tolua_cRoot_ForEachWorld); + tolua_beginmodule(tolua_S, "cRoot"); + tolua_function(tolua_S, "ForEachWorld", tolua_cRoot_ForEachWorld); tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S,"cWorld"); - tolua_function(tolua_S,"ForEachPlayer",tolua_cWorld_ForEachPlayer); + + tolua_beginmodule(tolua_S, "cWorld"); + tolua_function(tolua_S, "ForEachPlayer", tolua_cWorld_ForEachPlayer); + tolua_function(tolua_S, "ForEachEntity", tolua_cWorld_ForEachEntity); + tolua_function(tolua_S, "ForEachEntityInChunk", tolua_cWorld_ForEachEntityInChunk); tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S,"cPlugin"); - tolua_function(tolua_S,"GetCommands",tolua_cPlugin_GetCommands); - tolua_function(tolua_S,"BindCommand",tolua_cPlugin_BindCommand); + + tolua_beginmodule(tolua_S, "cPlugin"); + tolua_function(tolua_S, "GetCommands", tolua_cPlugin_GetCommands); + tolua_function(tolua_S, "BindCommand", tolua_cPlugin_BindCommand); tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S,"cPluginManager"); - tolua_function(tolua_S,"GetAllPlugins",tolua_cPluginManager_GetAllPlugins); + + tolua_beginmodule(tolua_S, "cPluginManager"); + tolua_function(tolua_S, "GetAllPlugins", tolua_cPluginManager_GetAllPlugins); tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S,"cPlayer"); - tolua_function(tolua_S,"GetGroups",tolua_cPlayer_GetGroups); - tolua_function(tolua_S,"GetResolvedPermissions",tolua_cPlayer_GetResolvedPermissions); + + tolua_beginmodule(tolua_S, "cPlayer"); + tolua_function(tolua_S, "GetGroups", tolua_cPlayer_GetGroups); + tolua_function(tolua_S, "GetResolvedPermissions", tolua_cPlayer_GetResolvedPermissions); tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S,"cWebPlugin_Lua"); - tolua_function(tolua_S,"AddTab",tolua_cWebPlugin_Lua_AddTab); + + tolua_beginmodule(tolua_S, "cWebPlugin_Lua"); + tolua_function(tolua_S, "AddTab", tolua_cWebPlugin_Lua_AddTab); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"HTTPRequest","HTTPRequest","",NULL); @@ -519,12 +623,12 @@ void ManualBindings::Bind( lua_State* tolua_S ) tolua_variable(tolua_S,"FormData",tolua_get_HTTPRequest_FormData,0); tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S,"cClientHandle"); - tolua_constant(tolua_S,"MIN_VIEW_DISTANCE",cClientHandle::MIN_VIEW_DISTANCE); - tolua_constant(tolua_S,"MAX_VIEW_DISTANCE",cClientHandle::MAX_VIEW_DISTANCE); + tolua_beginmodule(tolua_S, "cClientHandle"); + tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); + tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); tolua_endmodule(tolua_S); - tolua_function(tolua_S,"md5",tolua_md5); + tolua_function(tolua_S, "md5", tolua_md5); tolua_endmodule(tolua_S); } diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 98415b572..02d60b6bd 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -1473,6 +1473,23 @@ void cChunk::RemoveEntity(cEntity * a_Entity) +bool cChunk::ForEachEntity(cEntityCallback & a_Callback) +{ + // The entity list is locked by the parent chunkmap's CS + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) + { + if (a_Callback.Item(*itr)) + { + return false; + } + } // for itr - m_Entitites[] + return true; +} + + + + + BLOCKTYPE cChunk::GetBlock( int a_X, int a_Y, int a_Z ) { if ((a_X < 0) || (a_X >= Width) || (a_Y < 0) || (a_Y >= Height) || (a_Z < 0) || (a_Z >= Width)) return 0; // Clip diff --git a/source/cChunk.h b/source/cChunk.h index e24990982..7ebb37e43 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -40,7 +40,7 @@ class cPlayer; class cChunkMap; typedef std::list cClientHandleList; - +typedef cItemCallback cEntityCallback; @@ -143,6 +143,9 @@ public: void AddEntity( cEntity * a_Entity); void RemoveEntity( cEntity * a_Entity); + /// Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true + bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible + void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords void CalculateLighting(); // Recalculate right now diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index c2c26bae7..515741a62 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -932,6 +932,21 @@ void cChunkMap::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_Ch +bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + if ((Chunk == NULL) && !Chunk->IsValid()) + { + return false; + } + return Chunk->ForEachEntity(a_Callback); +} + + + + + void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cCSLock Lock(m_CSLayers); diff --git a/source/cChunkMap.h b/source/cChunkMap.h index 1d90c6aaa..df5cb5814 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -21,6 +21,7 @@ class cPlayer; typedef std::list cClientHandleList; typedef cChunk * cChunkPtr; +typedef cItemCallback cEntityCallback; @@ -126,6 +127,9 @@ public: /// Removes the entity from the chunk specified void RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); + /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true + bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Lua-accessible + /// Touches the chunk, causing it to be loaded or generated void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 7255cdc33..0eb621920 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -1566,7 +1566,7 @@ void cClientHandle::HandleUseEntity(cPacket_UseEntity * a_Packet) Callback.Instigator = m_Player; cWorld * World = m_Player->GetWorld(); - World->DoWithEntity( a_Packet->m_TargetID, Callback ); + World->DoWithEntityByID(a_Packet->m_TargetID, Callback); } diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 82243a8a9..0616fcf44 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -1602,23 +1602,6 @@ void cWorld::SendPlayerList(cPlayer * a_DestPlayer) -bool cWorld::DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback ) -{ - cCSLock Lock(m_CSEntities); - for (cEntityList::iterator itr = m_AllEntities.begin(); itr != m_AllEntities.end(); ++itr ) - { - if( (*itr)->GetUniqueID() == a_UniqueID ) - { - return a_Callback.Item(*itr); - } - } // for itr - m_AllEntities[] - return false; -} - - - - - void cWorld::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ) { m_ChunkMap->RemoveEntityFromChunk(a_Entity, a_ChunkX, a_ChunkY, a_ChunkZ); @@ -1637,6 +1620,49 @@ void cWorld::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, i +bool cWorld::ForEachEntity(cEntityCallback & a_Callback) +{ + cCSLock Lock(m_CSEntities); + for (cEntityList::iterator itr = m_AllEntities.begin(); itr != m_AllEntities.end(); ++itr ) + { + if (a_Callback.Item(*itr)) + { + return false; + } + } // for itr - m_AllEntities[] + return false; +} + + + + + +bool cWorld::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback) +{ + return m_ChunkMap->ForEachEntityInChunk(a_ChunkX, a_ChunkZ, a_Callback); +} + + + + + +bool cWorld::DoWithEntityByID( int a_UniqueID, cEntityCallback & a_Callback ) +{ + cCSLock Lock(m_CSEntities); + for (cEntityList::iterator itr = m_AllEntities.begin(); itr != m_AllEntities.end(); ++itr ) + { + if( (*itr)->GetUniqueID() == a_UniqueID ) + { + return a_Callback.Item(*itr); + } + } // for itr - m_AllEntities[] + return false; +} + + + + + void cWorld::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback) { m_ChunkMap->CompareChunkClients(a_ChunkX1, a_ChunkY1, a_ChunkZ1, a_ChunkX2, a_ChunkY2, a_ChunkZ2, a_Callback); diff --git a/source/cWorld.h b/source/cWorld.h index e557a56ed..c4ce91474 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -124,6 +124,7 @@ public: void AddPlayer( cPlayer* a_Player ); void RemovePlayer( cPlayer* a_Player ); + /// Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << unsigned int GetNumPlayers(); //tolua_export @@ -146,6 +147,15 @@ public: /// Moves the entity from its current chunk to the new chunk specified void MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); + + /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true + bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp + + /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true + bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp + + /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param + bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // TODO: Exported in ManualBindings.cpp /// Compares clients of two chunks, calls the callback accordingly void CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback); @@ -193,9 +203,6 @@ public: bool IsChunkLighted(int a_ChunkX, int a_ChunkZ); - // TODO: Export to Lua - bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback ); - void SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); //tolua_export void FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); //tolua_export char GetBlock( int a_X, int a_Y, int a_Z ); //tolua_export