08-13-17, 05:23 PM | #1 |
Making proxy table for _G
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:
Last edited by Thex : 08-13-17 at 07:17 PM. |
|
08-13-17, 06:44 PM | #2 |
Not sure whats the point of doing this in game. There are better tools to do this on the files you working with.
|
|
08-13-17, 06:56 PM | #3 |
Well it's mostly just cause it's fun to do, and it makes for some practice using metatables which i just recently learned about. But also i have been using the global scope too much on my past addons and would like to refactore them a bit, and such a tool could be useful (also i like having that cerberus table framework, which would allow me to use the same global container "name" for all my addons, so i'd like it to be like one tool ).
What other tools are you referring to? |
|
08-13-17, 08:07 PM | #4 |
If you using the environment control, you don't need to change the _G back at the end, and you won't write anything to the _G since your job is done in the private environment.
http://www.wowinterface.com/forums/s...5&postcount=11 With the environment control, we'll have more power with our codes, here is an example: Lua Code:
The "ture" is a spell error for 'true', and it'd be treated as nil, the code would run and we won't know the bug. With the environment control : Lua Code:
I also development plenty features based on it : http://www.wowinterface.com/forums/s...ad.php?t=55057 |
|
08-14-17, 03:06 AM | #5 | |
I maintain the stuff for Sublime Text 2-3: https://github.com/Resike/WoWDevelopment There is also a standalone exe which finds globals based on folders, or a luac build script (Made by Mik) which should work with every text editor that support build systems: http://www.wowinterface.com/download...OTANADDON.html |
||
08-14-17, 07:11 PM | #6 |
What you are interested in is called linting. A good linter for Lua is for example luacheck. For editor support check luacheck's related projects. One problem of that is that it does not support the WoW API, so calls to API functions will be treated as global access and you will get a warning for that. However not all global read/writes are bad and you can tell luacheck how to handle your specific case.
For your other use of sharing stuff between your addons, you would normally use a separate addon for this and list it as a required or optional dependency in the addons that are meant to use it. Basically you create a global table in it where all of your addons can add functionality or save state for use by other addons. It can also provide some basic API. This way you create a single global object and you don't litter _G. If you need a messaging system (like the event system in WoW) to notify interested parties of occurred changes, take a look at Callback-Handler-1.0. As for function environment control, please read the replies to the post that kurapica.igas linked in his/her reply. Both Phanx and SDPhantom explained what it is for and why such a proposal is an overreaction. |
|
08-19-17, 06:30 AM | #7 |
(Sorry for the delay, had a busy week )
@kurapica.igas Well now, that's pretty much 100% exactly what i wanted to be able to do At first i wanted to avoid stuff that would require the user to "register" every one of his files, but i've come to make peace with that idea, cause as you said, it removes the need to unregister the addon at the end of the loading, plus, it makes it able to catch global stuff declared within functions and other scopes, not only the ones declared on the global scope, which is great. So i changed my tool a little to make it so instead of displaying a warning if you put stuff as global, it catches those global stuff and puts them into an addon-specific table, so you don't have to worry about naming your stuff in a very specific way, nor do you need to put everything manually in an object (which is annoying to do in my opinion). I released this tool here, if any of you wants to take a look, and please don't hesitate to give me any feedback you might have, regarding optimization, conception or whatever subject I'm still fairly new to lua and i'll take any knowledge i can https://mods.curse.com/addons/wow/274928-cerberus @Rainrider Yep that's what i ended up doing, in the end; except i made it into one lua "library" file instead of a standalone addon, for simplicity i guess? I mean, as a developper, i like having this right in my files instead of somewhere else waiting for me to call upon it. For the event handler, i'm not sure why would one need a library for that? I mean it's nothing complicated. From the looks of the description, it seems like creating an eventsListener table with a Call() and Register() functions is all it does, which is approximatively 10 lines long in my addon @Resike Oh ok, got it. I didn't know sublime had that feature, that's pretty cool! |
|
08-25-17, 10:03 AM | #8 |
Although I've done plenty things with the environment control, I won't force you to try my way, I'll only provide suggestions based on your Cerberus :
Normally, the cost of calling meta-methods like __index isn't something so tiny that we can ignore. Take a simple exmaple, if we take every normal table access as 1 operation, every meta-method call as 1 operation, every global API call as 1 operation : Lua Code:
Within your environment, when we need to access the print API, we need 3 opers for your code g_cerberus[sCurrentlyLoadingAddonName][sKey] or _G[sKey] + 1 oper for the __index call. For the code print(GetUnitName("player")), we need total 4 (get GetUnitName) + 1( call the GetUnitName) + 4 (get print) + 1 (call the print) = 10 opers. So for the 100 loops, total is 1000 opers. If we call the code in the _G, the code print(GetUnitName("player")) should be 1 (get GetUnitName) + 1( call the GetUnitName) + 1 (get print) + 1 (call the print) = 4 opers. So for the 100 loops, total is 400 opers. So the cost can't be ignored. To solve it, we need cache the accessed global API or tables in the private environment, and for the next time the code access them, the __index meta-method will not be triggered again, since they already existed in the private environment, and the previous code'd run the same way just like in the _G. |
|
08-25-17, 10:14 AM | #9 |
Hm right; makes sense. I didn't really think too much about that cause i just assumed the call to __index was made wheter or not __index did something, but that's C++ thinking, i think i should stop thinking that way
I'll try to implement that, thanks for the suggestion! |
|
09-03-17, 08:36 AM | #10 |
Right, so i added the caching, and actually completely removed the initial proxy table, since it was actually useless in the end.
I think it should be better now. Thanks for your input! |
|
WoWInterface » Developer Discussions » Lua/XML Help » Making proxy table for _G |
«
Previous Thread
|
Next Thread
»
|
Display Modes |
Linear Mode |
Switch to Hybrid Mode |
Switch to Threaded Mode |
|
|