[IMPORTANT EDIT] Open-source code to get started on feeding your learning about get/setfenv


#1

IMPORTANT INFORMATION (EDIT)

This is in no way a reliable resource.

There are unchecked holes in the code and a number of deficiencies. The purpose of this resource is to get you started on trying to make sense of get/setfenv, but you should not directly use this model outside of a learning instrument for picking apart. The script example is also not at all a good set up. There is a low chance I will update this resource until I myself do a little bit more researching on environments. Proceed at your own risk.


Content

You will most likely not have any reason to use get/setfenv. I know I don’t. I made a model anyway and I open-sourced it some time back. I’m bringing it to the DevForum because I want to have a post in Community Resources and I feel like sharing this. Also in that respect, if you ever find yourself needing to use either get/setfenv, you have this which you can read, salvage or do whatever you want. You could even make a framework or system set up in this fashion.

Here you go: https://www.roblox.com/library/1292841947/API-Example

No, that isn’t really API. It’s a script I created after referencing what SyncAdmin did to have their commands work. In their plugins (commands, both ones that come with the model and ones that you can write), you can use certain methods off of “SyncAPI”. It gives a blue underline because it’s like an unknown global variable in-script, but methods actually work because SyncAPI is defined via setfenv in a private-source module.

SyncAPI.SomeFunctionFromTheAPI

^ Without setfenv, that normally wouldn’t work.

Leave feedback, comments or whatever below. Feel free to message me if you notice something off about my code as well - I am still learning and far from having a good arsenal of scripting knowledge and power.


#2

That’s pretty cool that you’ve taken the time to look into SyncAdmin. We do indeed use getfenv() and setfenv() for our custom API which allows game developers to create their own custom commands.

However, in addition to this, we also use metatables to lock the API table to prevent plugins from modifying the SyncAPI table.

This can be done by doing something like:

local apiInternal = {} --This is the table containing all the functions

--This is an example API function
function apiInternal.ExampleFunction(...)
    print("Example called with: ", ...)
end

local apiExposed = setmetatable({},{
    --This function is called whenever a script tries to read a value from apiExposed
    __index = function(_,key)
        --The function returns the value the read attempt should give
        return apiInternal[key]
    end;

    --This function is called whenever a script tries to write a new value to apiExposed
    __newindex = function(_,key,value)
        --We don't want people setting anything here, so just throw an error
        error("Cannot write to CustomAPI")
    end;

    --This table is returned whenever someone tries to read the metatable of apiExposed
    __metatable = {};
})

function test()
    CustomAPI.ExampleFunction("Hello","World")
end

local env = getfenv(test)
env.CustomAPI = apiExposed
setfenv(test,env)

It’s important to note that index and __index and __newindex are only called if that value doesn’t exist in the table the scripts are attempting to read/write. In our example, we pass an empty table as the first argument to setmetatable. setmetatable returns that empty table after setting its metatable, so apiExposed doesn’t actually contain any of the functions or values. It’s just a proxy to access the values in apiInternal.

Thanks!
~ ForPizzaSake & VolcanoINC