diff options
-rw-r--r-- | MCServer/Plugins/APIDump/APIDesc.lua | 29 | ||||
-rw-r--r-- | MCServer/Plugins/APIDump/main_APIDump.lua | 110 | ||||
-rw-r--r-- | MCServer/Plugins/Debuggers/Debuggers.lua | 75 | ||||
-rw-r--r-- | MCServer/Plugins/Debuggers/Info.lua | 6 | ||||
-rw-r--r-- | src/Bindings/AllToLua.pkg | 81 | ||||
-rw-r--r-- | src/Bindings/LuaWindow.h | 6 | ||||
-rw-r--r-- | src/Bindings/ManualBindings.cpp | 8 | ||||
-rw-r--r-- | src/BlockEntities/BlockEntityWithItems.h | 2 | ||||
-rw-r--r-- | src/Inventory.h | 2 | ||||
-rw-r--r-- | src/Map.h | 5 | ||||
-rw-r--r-- | src/Simulator/FloodyFluidSimulator.cpp | 3 | ||||
-rw-r--r-- | src/WebAdmin.h | 2 | ||||
-rw-r--r-- | src/World.cpp | 25 | ||||
-rw-r--r-- | src/main.cpp | 4 |
14 files changed, 281 insertions, 77 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 63fccb2f6..92cdb7415 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2871,41 +2871,18 @@ end This class represents the tolua bridge between the Lua API and MCServer. It supports some low level operations and queries on the objects. See also the tolua++'s documentation at {{http://www.codenix.com/~tolua/tolua++.html#utilities}}. Normally you shouldn't use any of these - functions except for cast() and type() + functions except for type() ]], Functions = { - cast = { Params = "Object, TypeStr", Return = "Object", Notes = "Casts the object to the specified type through the inheritance hierarchy." }, + cast = { Params = "Object, TypeStr", Return = "Object", Notes = "Casts the object to the specified type.<br/><b>Note:</b> This is a potentially unsafe operation and it could crash the server. There is normally no need to use this function at all, so don't use it unless you know exactly what you're doing." }, getpeer = { Params = "", Return = "", Notes = "" }, inherit = { Params = "", Return = "", Notes = "" }, releaseownership = { Params = "", Return = "", Notes = "" }, setpeer = { Params = "", Return = "", Notes = "" }, takeownership = { Params = "", Return = "", Notes = "" }, - type = { Params = "Object", Return = "TypeStr", Notes = "Returns a string representing the type of the object. This works similar to Lua's built-in type() function, but recognizes the underlying C++ types, too." }, + type = { Params = "Object", Return = "TypeStr", Notes = "Returns a string representing the type of the object. This works similar to Lua's built-in type() function, but recognizes the underlying C++ classes, too." }, }, - AdditionalInfo = - { - { - Header = "Usage example", - Contents = - [[ - The tolua.cast() function is normally used to cast between related types. For example in the - hook callbacks you often receive a generic {{cEntity}} object, when in fact you know that the - object is a {{cMonster}}. You can cast the object to access its cMonster functions: -<pre class="prettyprint lang-lua"> -function OnTakeDamage(a_ReceiverEntity, TDI) - if (a_ReceiverEntity.IsMob()) then - local Mob = tolua.cast(a_ReceiverEntity, "cMonster"); -- Cast a_ReceiverEntity into a {{cMonster}} instance - if (Mob:GetMonsterType() == cMonster.mtSheep) then - local Sheep = tolua.cast(Mob, "cSheep"); -- Cast Mob into a {{cSheep}} instance - -- Do something sheep-specific - end - end -end -</pre> - ]], - } - } -- AdditionalInfo }, -- tolua Globals = diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua index a25bab9cf..239bec69c 100644 --- a/MCServer/Plugins/APIDump/main_APIDump.lua +++ b/MCServer/Plugins/APIDump/main_APIDump.lua @@ -62,7 +62,7 @@ local function CreateAPITables() Variables = { }, Descendants = {}, -- Will be filled by ReadDescriptions(), array of class APIs (references to other member in the tree) - }}, + }, { Name = "cBlockArea", Functions = { @@ -78,7 +78,9 @@ local function CreateAPITables() Variables = { }, ... - }} + }, + + cCuboid = {} -- Each array item also has the map item by its name }; local Globals = { Functions = { @@ -135,7 +137,9 @@ local function CreateAPITables() (v ~= g_APIDesc) ) then if (type(v) == "table") then - table.insert(API, ParseClass(i, v)); + local cls = ParseClass(i, v) + table.insert(API, cls); + API[cls.Name] = cls else Add(Globals, i, v); end @@ -1449,6 +1453,103 @@ end +--- Returns true if a_Descendant is declared to be a (possibly indirect) descendant of a_Base +local function IsDeclaredDescendant(a_DescendantName, a_BaseName, a_API) + -- Check params: + assert(type(a_DescendantName) == "string") + assert(type(a_BaseName) == "string") + assert(type(a_API) == "table") + if not(a_API[a_BaseName]) then + return false + end + assert(type(a_API[a_BaseName]) == "table", "Not a class name: " .. a_BaseName) + assert(type(a_API[a_BaseName].Descendants) == "table") + + -- Check direct inheritance: + for _, desc in ipairs(a_API[a_BaseName].Descendants) do + if (desc.Name == a_DescendantName) then + return true + end + end -- for desc - a_BaseName's descendants + + -- Check indirect inheritance: + for _, desc in ipairs(a_API[a_BaseName].Descendants) do + if (IsDeclaredDescendant(a_DescendantName, desc.Name, a_API)) then + return true + end + end -- for desc - a_BaseName's descendants + + return false +end + + + + + +--- Checks the specified class' inheritance +-- Reports any problems as new items in the a_Report table +local function CheckClassInheritance(a_Class, a_API, a_Report) + -- Check params: + assert(type(a_Class) == "table") + assert(type(a_API) == "table") + assert(type(a_Report) == "table") + + -- Check that the declared descendants are really descendants: + local registry = debug.getregistry() + for _, desc in ipairs(a_Class.Descendants or {}) do + local isParent = false + local parents = registry["tolua_super"][_G[desc.Name]] + if not(parents[a_Class.Name]) then + table.insert(a_Report, desc.Name .. " is not a descendant of " .. a_Class.Name) + end + end -- for desc - a_Class.Descendants[] + + -- Check that all inheritance is listed for the class: + local parents = registry["tolua_super"][_G[a_Class.Name]] -- map of "classname" -> true for each class that a_Class inherits + for clsName, isParent in pairs(parents or {}) do + if ((clsName ~= "") and not(clsName:match("const .*"))) then + if not(IsDeclaredDescendant(a_Class.Name, clsName, a_API)) then + table.insert(a_Report, a_Class.Name .. " inherits from " .. clsName .. " but this isn't documented") + end + end + end +end + + + + + +--- Checks each class's declared inheritance versus the actual inheritance +local function CheckAPIDescendants(a_API) + -- Check each class: + local report = {} + for _, cls in ipairs(a_API) do + if (cls.Name ~= "Globals") then + CheckClassInheritance(cls, a_API, report) + end + end + + -- If there's anything to report, output it to a file: + if (report[1] ~= nil) then + LOG("There are inheritance errors in the API description:") + for _, msg in ipairs(report) do + LOG(" " .. msg) + end + + local f, err = io.open("API/_inheritance_errors.txt", "w") + if (f == nil) then + LOG("Cannot report inheritance problems to a file: " .. tostring(err)) + return + end + f:write(table.concat(report, "\n")) + f:close() + end +end + + + + + local function DumpApi() LOG("Dumping the API...") @@ -1501,6 +1602,9 @@ local function DumpApi() LOG("Reading descriptions..."); ReadDescriptions(API); + -- Check that the API lists the inheritance properly, report any problems to a file: + CheckAPIDescendants(API) + -- Dump all available API objects in HTML format into a subfolder: DumpAPIHtml(API); diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 9ea623b64..d0c362ab4 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -1643,6 +1643,81 @@ end +--- Monitors the state of the "inh" entity-spawning hook +-- if false, the hook is installed before the "inh" command processing +local isInhHookInstalled = false + +function HandleConsoleInh(a_Split, a_FullCmd) + -- Check the param: + local kindStr = a_Split[2] or "pkArrow" + local kind = cProjectileEntity[kindStr] + if (kind == nil) then + return true, "There's no projectile kind '" .. kindStr .. "'." + end + + -- Get the world to test in: + local world = cRoot:Get():GetDefaultWorld() + if (world == nil) then + return true, "Cannot test inheritance, no default world" + end + + -- Install the hook, if needed: + if not(isInhHookInstalled) then + cPluginManager:AddHook(cPluginManager.HOOK_SPAWNING_ENTITY, + function (a_CBWorld, a_CBEntity) + LOG("New entity is spawning:") + LOG(" Lua type: '" .. type(a_CBEntity) .. "'") + LOG(" ToLua type: '" .. tolua.type(a_CBEntity) .. "'") + LOG(" GetEntityType(): '" .. a_CBEntity:GetEntityType() .. "'") + LOG(" GetClass(): '" .. a_CBEntity:GetClass() .. "'") + end + ) + isInhHookInstalled = true + end + + -- Create the projectile: + LOG("Creating a " .. kindStr .. " projectile in world " .. world:GetName() .. "...") + local msg + world:ChunkStay({{0, 0}}, + nil, + function () + -- Create a projectile at {8, 100, 8}: + local entityID = world:CreateProjectile(8, 100, 8, kind, nil, nil) + if (entityID < 0) then + msg = "Cannot test inheritance, projectile creation failed." + return + end + LOG("Entity created, ID #" .. entityID) + + -- Call a function on the newly created entity: + local hasExecutedCallback = false + world:DoWithEntityByID( + entityID, + function (a_CBEntity) + LOG("Projectile created and found using the DoWithEntityByID() callback") + LOG("Lua type: '" .. type(a_CBEntity) .. "'") + LOG("ToLua type: '" .. tolua.type(a_CBEntity) .. "'") + LOG("GetEntityType(): '" .. a_CBEntity:GetEntityType() .. "'") + LOG("GetClass(): '" .. a_CBEntity:GetClass() .. "'") + hasExecutedCallback = true + end + ) + if not(hasExecutedCallback) then + msg = "The callback failed to execute" + return + end + + msg = "Inheritance test finished" + end + ) + + return true, msg +end + + + + + function HandleConsoleLoadChunk(a_Split) -- Check params: local numParams = #a_Split diff --git a/MCServer/Plugins/Debuggers/Info.lua b/MCServer/Plugins/Debuggers/Info.lua index e062a8d8c..0370145df 100644 --- a/MCServer/Plugins/Debuggers/Info.lua +++ b/MCServer/Plugins/Debuggers/Info.lua @@ -212,6 +212,12 @@ g_PluginInfo = HelpString = "Tests the crypto hashing functions", }, + ["inh"] = + { + Handler = HandleConsoleInh, + HelpString = "Tests the bindings of the cEntity inheritance", + }, + ["loadchunk"] = { Handler = HandleConsoleLoadChunk, diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 7e174e770..8f55eba07 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -1,4 +1,19 @@ +// AllToLua.pkg + +// Defines the bindings that are exported to Lua by the ToLua processor + +/* + Each file referenced in the $cfile is parsed by ToLua, and bindings are generated for classes and functions +marked with "// tolua_export", or between the "// tolua_begin" and "// tolua_end" markers. + + Note that if class D inherits from class B, then class B needs to be parsed before class D, otherwise the +inheritance doesn't work properly (#1789). +*/ + + + + $#include "../Globals.h" // Typedefs from Globals.h, so that we don't have to process that file: @@ -27,14 +42,38 @@ $cfile "WebPlugin.h" $cfile "LuaWindow.h" $cfile "../BlockID.h" -$cfile "../Mobs/MonsterTypes.h" $cfile "../BlockInfo.h" $cfile "../StringUtils.h" $cfile "../Defines.h" $cfile "../ChatColor.h" $cfile "../ClientHandle.h" -$cfile "../Entities/ArrowEntity.h" +$cfile "../Server.h" +$cfile "../World.h" +$cfile "../Inventory.h" +$cfile "../Enchantments.h" +$cfile "../Item.h" +$cfile "../ItemGrid.h" +$cfile "../WebAdmin.h" +$cfile "../Root.h" +$cfile "../Cuboid.h" +$cfile "../BoundingBox.h" +$cfile "../Tracer.h" +$cfile "../BlockArea.h" +$cfile "../Generating/ChunkDesc.h" +$cfile "../CraftingRecipes.h" +$cfile "../UI/Window.h" +$cfile "../CompositeChat.h" +$cfile "../Map.h" +$cfile "../MapManager.h" +$cfile "../Scoreboard.h" +$cfile "../Statistics.h" +$cfile "../Protocol/MojangAPI.h" + +// Entities: $cfile "../Entities/Entity.h" +$cfile "../Entities/Pawn.h" +$cfile "../Entities/ProjectileEntity.h" +$cfile "../Entities/ArrowEntity.h" $cfile "../Entities/EntityEffect.h" $cfile "../Entities/ExpBottleEntity.h" $cfile "../Entities/FireChargeEntity.h" @@ -43,25 +82,21 @@ $cfile "../Entities/Floater.h" $cfile "../Entities/GhastFireballEntity.h" $cfile "../Entities/HangingEntity.h" $cfile "../Entities/ItemFrame.h" -$cfile "../Entities/Pawn.h" $cfile "../Entities/Player.h" $cfile "../Entities/Painting.h" $cfile "../Entities/Pickup.h" -$cfile "../Entities/ProjectileEntity.h" $cfile "../Entities/SplashPotionEntity.h" $cfile "../Entities/ThrownEggEntity.h" $cfile "../Entities/ThrownEnderPearlEntity.h" $cfile "../Entities/ThrownSnowballEntity.h" $cfile "../Entities/TNTEntity.h" $cfile "../Entities/WitherSkullEntity.h" -$cfile "../Server.h" -$cfile "../World.h" -$cfile "../Inventory.h" -$cfile "../Enchantments.h" -$cfile "../Item.h" -$cfile "../ItemGrid.h" -$cfile "../BlockEntities/BeaconEntity.h" +$cfile "../Mobs/MonsterTypes.h" +$cfile "../Mobs/Monster.h" + +// Block entities: $cfile "../BlockEntities/BlockEntity.h" +$cfile "../BlockEntities/BeaconEntity.h" $cfile "../BlockEntities/BlockEntityWithItems.h" $cfile "../BlockEntities/ChestEntity.h" $cfile "../BlockEntities/CommandBlockEntity.h" @@ -76,30 +111,6 @@ $cfile "../BlockEntities/SignEntity.h" $cfile "../BlockEntities/MobHeadEntity.h" $cfile "../BlockEntities/MobSpawnerEntity.h" $cfile "../BlockEntities/FlowerPotEntity.h" -$cfile "../WebAdmin.h" -$cfile "../Root.h" -$cfile "../Cuboid.h" -$cfile "../BoundingBox.h" -$cfile "../Tracer.h" -$cfile "../BlockArea.h" -$cfile "../Generating/ChunkDesc.h" -$cfile "../CraftingRecipes.h" -$cfile "../UI/Window.h" -$cfile "../Mobs/Monster.h" -$cfile "../CompositeChat.h" -$cfile "../Map.h" -$cfile "../MapManager.h" -$cfile "../Scoreboard.h" -$cfile "../Statistics.h" -$cfile "../Protocol/MojangAPI.h" - - - - - -// Need to declare this class so that the usertype is properly registered in Bindings.cpp - -// it seems impossible to register a usertype in ManualBindings.cpp -class cLineBlockTracer; diff --git a/src/Bindings/LuaWindow.h b/src/Bindings/LuaWindow.h index 76530d99d..d4fc58660 100644 --- a/src/Bindings/LuaWindow.h +++ b/src/Bindings/LuaWindow.h @@ -35,8 +35,10 @@ This reference needs to be unreferenced in the Destroy() function. */ // tolua_begin class cLuaWindow : - public cWindow, - public cItemGrid::cListener + public cWindow + // tolua_end + , public cItemGrid::cListener + // tolua_begin { typedef cWindow super; diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 40ac12b41..035be55ae 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -638,11 +638,11 @@ static int tolua_DoWithID(lua_State* tolua_S) private: virtual bool Item(Ty2 * a_Item) override { - lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); // Push function to call - tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); // Push the item + lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); // Push function to call + tolua_pushusertype(LuaState, a_Item, a_Item->GetClass()); // Push the item if (TableRef != LUA_REFNIL) { - lua_rawgeti(LuaState, LUA_REGISTRYINDEX, TableRef); // Push the optional callbackdata param + lua_rawgeti(LuaState, LUA_REGISTRYINDEX, TableRef); // Push the optional callbackdata param } int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); @@ -3677,6 +3677,8 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_cclass(tolua_S, "cCryptoHash", "cCryptoHash", "", nullptr); tolua_usertype(tolua_S, "cStringCompression"); tolua_cclass(tolua_S, "cStringCompression", "cStringCompression", "", nullptr); + tolua_usertype(tolua_S, "cLineBlockTracer"); + tolua_cclass(tolua_S, "cLineBlockTracer", "cLineBlockTracer", "", nullptr); // Globals: tolua_function(tolua_S, "Clamp", tolua_Clamp); diff --git a/src/BlockEntities/BlockEntityWithItems.h b/src/BlockEntities/BlockEntityWithItems.h index 2c2ced1cb..740dbca51 100644 --- a/src/BlockEntities/BlockEntityWithItems.h +++ b/src/BlockEntities/BlockEntityWithItems.h @@ -21,7 +21,9 @@ // tolua_begin class cBlockEntityWithItems : public cBlockEntity, + // tolua_end public cItemGrid::cListener, + // tolua_begin public cBlockEntityWindowOwner { typedef cBlockEntity super; diff --git a/src/Inventory.h b/src/Inventory.h index 4e76bc0d3..311f64562 100644 --- a/src/Inventory.h +++ b/src/Inventory.h @@ -31,7 +31,9 @@ You can use the invArmorOffset, invInventoryOffset and invHotbarOffset constants */ class cInventory : + // tolua_end public cItemGrid::cListener + // tolua_begin { public: @@ -189,6 +189,11 @@ public: return "cMap"; } + const char * GetClass(void) // Needed for ManualBindings' DoWith templates + { + return "cMap"; + } + protected: diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index bcd083294..a9481edb0 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -108,8 +108,9 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re { SpreadXZ(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta); } + // If source creation is on, check for it here: - else if ( + if ( (m_NumNeighborsForSource > 0) && // Source creation is on (MyMeta == m_Falloff) && // Only exactly one block away from a source (fast bail-out) !IsPassableForFluid(Below) && // Only exactly 1 block deep diff --git a/src/WebAdmin.h b/src/WebAdmin.h index 86a8a9a4b..1e1a9bfa9 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -95,7 +95,9 @@ struct sWebAdminPage // tolua_begin class cWebAdmin : + // tolua_end public cHTTPServer::cCallbacks + // tolua_begin { public: // tolua_end diff --git a/src/World.cpp b/src/World.cpp index f3837eb02..292ff9b94 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -714,6 +714,7 @@ void cWorld::GenerateRandomSpawn(void) bool cWorld::CheckPlayerSpawnPoint(int a_PosX, int a_PosY, int a_PosZ) { + // Check that spawnblock and surrounding blocks are neither solid nor water / lava static const struct { int x, z; @@ -725,26 +726,22 @@ bool cWorld::CheckPlayerSpawnPoint(int a_PosX, int a_PosY, int a_PosZ) { 0, -1 }, { 0, 1 }, }; - - // Checking that spawnblock and surrounding blocks are air and not water/lava for (size_t i = 0; i < ARRAYCOUNT(Coords); i++) { BLOCKTYPE BlockType = GetBlock(a_PosX + Coords[i].x, a_PosY, a_PosZ + Coords[i].x); - if (cBlockInfo::IsSolid(BlockType) || IsBlockLiquid(BlockType)) { return false; } } // for i - Coords[] - // Check if block below is solid - BLOCKTYPE BlockType = GetBlock(a_PosX, a_PosY - 1, a_PosZ); - if (!cBlockInfo::IsSolid(BlockType)) + // Check that the block below is solid: + if (!cBlockInfo::IsSolid(GetBlock(a_PosX, a_PosY - 1, a_PosZ))) { return false; } - // Checking that all the blocks above the spawnpoint is air. + // Check that all the blocks above the spawnpoint are not solid: for (int i = a_PosY; i < cChunkDef::Height; i++) { BLOCKTYPE BlockType = GetBlock(a_PosX, i, a_PosZ); @@ -2911,6 +2908,20 @@ bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_ bool cWorld::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) { + // First check the entities-to-add: + { + cCSLock Lock(m_CSEntitiesToAdd); + for (auto & ent: m_EntitiesToAdd) + { + if (ent->GetUniqueID() == a_UniqueID) + { + a_Callback.Item(ent); + return true; + } + } // for ent - m_EntitiesToAdd[] + } + + // Then check the chunkmap: return m_ChunkMap->DoWithEntityByID(a_UniqueID, a_Callback); } diff --git a/src/main.cpp b/src/main.cpp index 20609a2f8..428e89e93 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -282,8 +282,12 @@ int main( int argc, char **argv) } } // for i - argv[] + // Initialize logging subsystem: cLogger::InitiateMultithreading(); + // Initialize LibEvent: + cNetworkSingleton::Get(); + #if !defined(ANDROID_NDK) try #endif |