我最近开始创建一个脚本构建器。我坚持的唯一部分是让沙箱工作。
我尝试过本教程:http://wiki.roblox.com/index.php?title=Sandboxing但无效
我完全不明白如何做到这一点,但我设法做到了这一点:
local needssandboxing = function(i) end
sandbox = {}
sandbox.cache = {}
local function safeDestroy(obj)
if obj.ClassName == "Script" then
print("You cannot destroy a Script")
elseif obj == "Base" then
print("You cannot destroy the Base.")
end
obj:Destroy()
end
local function safeGetChildren(obj)
local res = {}
for k,v in pairs(obj:GetChildren()) do
if not v.Name:match("^Hide") then
table.insert(res,v)
end
end
return res
end
sandbox.mt = {
__index = function(self, k)
local original = sandbox.cache[self]
local v = original[k]
if k:lower() == "destroy" then
return sandbox.any(safeDestroy)
elseif k:lower() == "getchildren" or k:lower() == "children" then
return sandbox.any(safeGetChildren)
end
return sandbox.any(v)
end,
__newindex = function(self, k, v)
local original = sandbox.cache[self]
original[k] = unsandbox.any(v)
end
}
function sandbox.any(a)
if sandbox.cache[a] then
return a
elseif type(a) == "function" then
return sandbox.func(a)
elseif type(a) == "table" then
return sandbox.table(a)
else
return value
end
end
function sandbox.object(o)
local sandboxed = setmetatable({}, sandbox.mt)
sandbox.cache[sandboxed] = o
return sandboxed
end
function sandbox.func(f)
local sandboxed = function(...)
return sandbox(f(unsandbox(...)))
end
sandbox.cache[sandboxed] = f
return sandboxed
end
function sandbox.table(t)
local sandboxed = {}
for k, v in pairs(t) do
sandboxed[sandbox.any(k)] = sandbox.any(v)
end
return sandboxed
end
unsandbox = {}
unsandbox.any = function(a)
if sandbox.cache[a] then
return sandbox.cache[a]
elseif type(a) == "function" then
return unsandbox.func(a)
elseif type(a) == "table" then
return unsandbox.table(a)
else
return a
end
end
unsandbox.table = function(t)
local unsandboxed = {}
for k, v in pairs(t) do
unsandboxed[unsandbox.any(k)] = unsandbox.any(v)
end
return unsandboxed
end
unsandbox.func = function(f)
local raw = function(...)
return unsandbox(f(sandbox(...)))
end
sandbox.cache[f] = raw
return raw
end
local callable_mt = {
__call = function(self, first, ...)
if select('#', ...) == 0 then
return self.any(first)
else
return self.any(first), self(...)
end
end
}
setmetatable(sandbox, callable_mt)
setmetatable(unsandbox, callable_mt)
但我不知道如何正确使用它。我试过了:
sandbox(function()
local r = game.Workspace:GetChildren()
for i=1, #r do
print(r[i])
end
end)
这绝对没有。有什么我做错了吗?
答案 0 :(得分:1)
沙箱本身不是一个功能,但__call
元方法允许它被称为函数,即使它是一个表。
您的代码必须使用以下代码放在脚本中。 然后,当您希望加载脚本时,将StringValue命名为" Code"在脚本中,将Value属性设置为您要执行的脚本:
local realEnvironment = getfenv(0);
local fakeEnvironment = setmetatable({}, {__index = function (self, i)
if (realEnvironment[i]) then --Check if object exists at all
return sandbox(realEnvironment[i]) --return sandboxed object
end;
end, __metatable = 'This is a locked metatable!'}); --An environment to only return sandboxed objects
setfenv(0,fakeEnvironment);--Set the global environment
setfenv(1,fakeEnvironment);--Set the current function stack
assert(loadstring(script:WaitForChild('Code').Value))();
最后一行等待' Code' child,然后在其上调用loadstring
,assert将检查它是否有语法错误,如果它有,它将会出错,如果没有它返回函数然后被调用(不需要设置函数的ENV)因为我们设定了全球环境。)