0

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

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

那绝对没有任何作用。有什么我做错了吗?

4

2 回答 2

1

在您的代码中,没有 function sandbox(),因此您试图调用一个不存在的函数。

尝试这个:

sandbox.func(function()
    local r = game.Workspace:GetChildren()
    for i=1, #r do
        print(r[i])
    end
end)
于 2015-09-19T17:54:50.923 回答
1

沙盒本身不是一个函数,但元__call方法允许它作为一个函数被调用,即使它是一个表。

您的代码必须放在具有以下代码的脚本中。然后,当您希望加载脚本时,将名为“Code”的 StringValue 放入脚本中,并将 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))();

最后一行等待“代码”子级,然后调用loadstring它,断言将检查它是否有语法错误,如果有,则会出错,如果没有,则返回随后调用的函数(无需设置 ENV的功能,因为我们设置了全局环境)。

于 2016-11-22T17:47:24.717 回答