summaryrefslogtreecommitdiffstats
path: root/MCServer
diff options
context:
space:
mode:
Diffstat (limited to 'MCServer')
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua29
-rw-r--r--MCServer/Plugins/APIDump/main_APIDump.lua110
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua75
-rw-r--r--MCServer/Plugins/Debuggers/Info.lua6
4 files changed, 191 insertions, 29 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,