Please explain this complex code

I was looking through code for btools so I could check how they used handles to resize things. Then at line 61-63 I got confused by how they could call a function without it existing
Code:

Core = require(Tool.Core);
SnapTracking = require(Tool.Core.Snapping);

-- Services
local ContextActionService = game:GetService 'ContextActionService'
local Workspace = game:GetService 'Workspace'

-- Libraries
local Libraries = Tool:WaitForChild 'Libraries'
local Signal = require(Libraries:WaitForChild 'Signal')
local Make = require(Libraries:WaitForChild 'Make')
local ListenForManualWindowTrigger = require(Tool.Core:WaitForChild('ListenForManualWindowTrigger'))

-- Import relevant references
Selection = Core.Selection;
Support = Core.Support;
Security = Core.Security;
Support.ImportServices();

-- Initialize the tool
local ResizeTool = {
	Name = 'Resize Tool';
	Color = BrickColor.new 'Cyan';

	-- Default options
	Increment = 1;
	Directions = 'Normal';
}

ResizeTool.ManualText = [[<font face="GothamBlack" size="16">Resize Tool  đź› </font>
Allows you to resize parts.<font size="12"><br /></font>
<font size="12" color="rgb(150, 150, 150)"><b>Directions</b></font>
Lets you choose in which directions to resize the part.<font size="6"><br /></font>

<b>TIP: </b>Click on a part to focus the handles on it.<font size="6"><br /></font>

<b>TIP: </b>Hit <b>Enter</b> to switch between directions quickly.<font size="12"><br /></font>

<font size="12" color="rgb(150, 150, 150)"><b>Increment</b></font>
Lets you choose how many studs to resize by.<font size="6"><br /></font>

<b>TIP: </b>Hit the – key to quickly type increments.<font size="6"><br /></font>

<b>TIP: </b>Use your number pad to resize exactly by the current increment. Holding <b>Shift</b> reverses the increment.<font size="4"><br /></font>
   <font color="rgb(150, 150, 150)">•</font>  8 & 2 — up & down
   <font color="rgb(150, 150, 150)">•</font>  1 & 9 — back & forth
   <font color="rgb(150, 150, 150)">•</font>  4 & 6 — left & right<font size="12"><br /></font>

<font size="12" color="rgb(150, 150, 150)"><b>Snapping</b></font>
Hold the <b><i>R</i></b> key, and <b>click and drag the snap point</b> of a part (in the direction you want to resize) towards the snap point of another part, to resize up to that point.
]]

-- Container for temporary connections (disconnected automatically)
local Connections = {};

function ResizeTool.Equip()
	-- Enables the tool's equipped functionality

	-- Start up our interface
	ShowUI();
	ShowHandles();
	BindShortcutKeys();

end;
2 Likes

If those functions aren’t defined in the code, it’s likely one of the ModuleScripts is importing them into the environment via setfenv().

From the look of it, Support.ImportServices() is likely the one adding those functions to the script.

4 Likes

Adding into this, you really shouldn’t do stuff like that. Most code in the toolbox is really outdated and slow due to things like that.

3 Likes

Yeah, you can do this:

getfenv()['ShowUI'] = function()
-- do whatever
end

which btw is impractical. But I don’t know how they would’ve done it as calling getfenv will return the environment of the script the function is from (module script).

1 Like

You use setfenv() with the stack level and new environment:

local t = {}

function t.set(var)
	setfenv(2, setmetatable({ --> replace the environment 2 stacks above the current one
		setValue = var --> add a custom variable to the environment (global)
	}, {
		__index = getfenv()
	}))
end

t.set(12)
print(setValue) --> 12

Edit: You don’t have to use a table either.

Without Table
local function set(var)
	setfenv(2, setmetatable({ --> replace the environment 2 stacks above the current one
		setValue = var --> add a custom variable to the environment (global)
	}, {
		__index = getfenv()
	}))
end

set(12)
print(setValue) --> 12
1 Like

This was the only thing I could find but it wasn’t even in the Core module

function SupportLibrary.ImportServices()
	-- Adds references to common services into the calling environment

	-- Get the calling environment
	local CallingEnvironment = getfenv(2);
	-- Add the services
	CallingEnvironment.Workspace = Game:GetService 'Workspace';
	CallingEnvironment.Players = Game:GetService 'Players';
	CallingEnvironment.MarketplaceService = Game:GetService 'MarketplaceService';
	CallingEnvironment.ContentProvider = Game:GetService 'ContentProvider';
	CallingEnvironment.SoundService = Game:GetService 'SoundService';
	CallingEnvironment.UserInputService = Game:GetService 'UserInputService';
	CallingEnvironment.SelectionService = Game:GetService 'Selection';
	CallingEnvironment.CoreGui = Game:GetService 'CoreGui';
	CallingEnvironment.HttpService = Game:GetService 'HttpService';
	CallingEnvironment.ChangeHistoryService = Game:GetService 'ChangeHistoryService';
	CallingEnvironment.ReplicatedStorage = Game:GetService 'ReplicatedStorage';
	CallingEnvironment.GroupService = Game:GetService 'GroupService';
	CallingEnvironment.ServerScriptService = Game:GetService 'ServerScriptService';
	CallingEnvironment.ServerStorage = Game:GetService 'ServerStorage';
	CallingEnvironment.StarterGui = Game:GetService 'StarterGui';
	CallingEnvironment.RunService = Game:GetService 'RunService';
end;

since you seem to know a lot about setfenv() and getfenv() can you explain what they do?

They allow you to manipulate the stack’s environment (variables, functions, etc). When you use getfenv(), you’re retrieving the current stack and all the global variables in the stack; when you use setfenv() you’re setting (and overwriting) the globals for either the stack, or a given function.

Example with metatable

local function c_stack()
    print(hello) --> prints "world!"
end

setfenv(c_stack, setmetatable({
    hello = "world!"
}, {__index=getfenv()})

c_stack()

Example without metatable

local function c_stack()
    print(hello) --> errors (attempt to call a nil value)
    -- since the environment was overwriten to { hello = "world!" },
    -- built-in globals (like print or game) no longer exist in the environment and must be
    -- explicitly defined (this is why a metatable pointing to the default
    -- environment was used in the first example).
end

setfenv(c_stack, {
    hello = "world!"
})

c_stack()

I’d advise against using these though since they de-optimize the Luau environment in order to function, which can lead to worse performance for your code (and they’re deprecated).

getfenv()
setfenv()

(Make sure you turn on “Show Deprecated” at the top of the page to see their documentation)

oh thats rather interesting, thank you

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.