Roblox Script Builder Sandbox

时间:2015-07-31 04:34:35

标签: roblox

我最近开始创建一个脚本构建器。我坚持的唯一部分是让沙箱工作。

我尝试过本教程: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)

这绝对没有。有什么我做错了吗?

1 个答案:

答案 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)因为我们设定了全球环境。)