Hi,
I'm currently trying to develop a small tool to help with addons creation. The point would be that said tool would "detect" all functions and variables declared in the global scope, and print a warning saying like "don't use global scope" or something, just to help catching mistakes.
So i set up a proxy table for the _G table. I created a copy of it, then _G = {}, and gave it __newindex and __index metamethods to redirect all transit. At the end of the addon loading, i'm resetting _G to its original form, to avoid other addons using this.
Issue i'm having is that apparently, changing the value of _G directly (either by doing "_G = {}" or even "_G = _G") is not allowed, and makes you, oddly enough, unable to use your spellbar hotkeys (prompting a popup "[Your addon] has been blocked from an action only available to the Blizzard UI".
So i'm kind of sad to see that; and i was wondering if you guys had any idea how to bypass that issue (or how to make it more "secure" i guess, in the eyes of the API), please?
Edit: One way i could think of would be to create a local _G = GetFakeG() at the beginning of all of my scripts, where GetFakeG() would just give me an empty table with the indirection metatable, created in my cerberus.lua file; but that would mean having to get that local _G in every script, and that's something i would like to avoid. I'd like this tool to be "install, initialize and forget about it".
(Here is my code, just in case you're wondering about anything: )
Lua Code:
local cerberusTextColour = "ffc42727";
local cerberusPrefix = "|c" .. cerberusTextColour .. "Cerberus: |r"
function Cerberus_Print(message)
print(cerberusPrefix .. message);
end
g_cerberus = g_cerberus or {};
local currentAddonName = nil;
local function GetCurrentAddonName()
return currentAddonName;
end
g_cerberus._G = function()
return g_cerberus[GetCurrentAddonName()]; -- Using getter function to avoid conflicts between mods
end
g_cerberus.RegisterAddon = function(addonName)
if g_cerberus._G() ~= nil then
Cerberus_Print("Attempting to register addon which has already been registered (" .. addonName .. "). Try with a different addon name, or a more specific one.");
return;
end
currentAddonName = addonName;
g_cerberus[addonName] = {};
g_cerberus[addonName]._GCopy = _G;
_G = {};
setmetatable(_G,
{
__newindex = function(_, key, value)
Cerberus_Print("Attempting to store " .. (key or "nil") .. " in the global scope with value \"" .. tostring(value) .. "\". Make sure that's what you actually want.");
g_cerberus._G()._GCopy[key] = value;
end,
__index = function(_, key)
return g_cerberus._G()._GCopy[key];
end
});
end
----- In another file to put at the end of the toc list
if g_cerberus ~= nil and g_cerberus._G() ~= nil and g_cerberus._G()._GCopy ~= nil then
_G = g_cerberus._G()._GCopy;
end