Advertisement
einsteinK

ROBLOX - Simple wrapped instance sandbox

Apr 29th, 2016
678
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 4.61 KB | None | 0 0
  1. --[[
  2.     Simple (well, simplish) sandbox that allows wrapping of instances:
  3.    
  4.     local wrapped,properties = Instance.wrap(someInstance)
  5.    
  6.     properties.PROP = true
  7.     print(wrapped.PROP) --> nil (works)
  8.     wrapped.PROP = 123 (works)
  9.     print(wrapped.PROP) --> 123 (works)
  10.    
  11.     print(wrapped.DERP) (error)
  12.     wrapped.DERP = 123 (error)
  13.    
  14.     print(wrapped.Name) (works)
  15.     wrapped.Name = "Idk" (works)
  16.    
  17.     wrapped.Parent = realInstance (works)
  18.     anotherRealInstance.Parent = wrapped (works)
  19.     wrapped:Destroy() (works)
  20.    
  21.     Instance.new("Folder",wrapped) (works)
  22. --]]
  23.  
  24. local RealToFake = setmetatable({},{__mode="v"})
  25. local FakeToReal = setmetatable({},{__mode="k"})
  26.  
  27. local function isInstance(obj)
  28.     return pcall(game.GetService,game,obj)
  29. end
  30.  
  31. local instaMeta,sandbox = {}
  32. function instaMeta:__tostring()
  33.     return self.Name
  34. end instaMeta.__metatable = "Locked"
  35. function instaMeta:__index(key)
  36.     local real = FakeToReal[self]
  37.     return sandbox(real[key])
  38. end
  39. function instaMeta:__newindex(key,val)
  40.     local real = FakeToReal[self]
  41.     real[key] = FakeToReal[val] or val
  42. end
  43. local function wrapInstance(obj)
  44.     return setmetatable({},instaMeta)
  45. end
  46.  
  47. local function register(fake,real)
  48.     RealToFake[real] = fake
  49.     FakeToReal[fake] = real
  50. end
  51.  
  52. local sandboxTuple,unsandboxTuple
  53.  
  54. function sandbox(obj)
  55.     if RealToFake[obj] then
  56.         return RealToFake[obj]
  57.     elseif type(obj) == "userdata" and isInstance(obj) then
  58.         local wrapped = wrapInstance(obj)
  59.         register(wrapped,obj) return wrapped
  60.     elseif type(obj) == "function" then
  61.         local wrapped = function(...)
  62.             return sandboxTuple(obj(unsandboxTuple(...)))
  63.         end register(wrapped,obj) return wrapped
  64.     end return obj
  65. end
  66.  
  67. function sandboxTuple(...)
  68.     local num = select("#",...)
  69.     local res = {...}
  70.     for k,v in pairs(res) do
  71.         if type(v) == "table" then
  72.             local res = {}
  73.             for a,b in pairs(v) do
  74.                 res[sandbox(a)] = sandbox(b)
  75.             end v = res
  76.         end res[k] = sandbox(v)
  77.     end return unpack(res,1,num)
  78. end
  79. function unsandboxTuple(...)
  80.     local num = select("#",...)
  81.     local res = {...}
  82.     for k,v in pairs(res) do
  83.         if type(v) == "table" and not FakeToReal[v] then
  84.             local res = {}
  85.             for a,b in pairs(v) do
  86.                 local c = FakeToReal[a]
  87.                 local d = FakeToReal[b]
  88.                 res[c or a] = d or b
  89.             end v = res
  90.         end res[k] = FakeToReal[v] or v
  91.     end return unpack(res,1,num)
  92. end
  93.  
  94. local real,envMeta = getfenv(),{}
  95. function envMeta:__index(key)
  96.     return key ~= "script" and sandbox(real[key]) or nil
  97. end
  98.  
  99. local lockedMeta = {}
  100. function lockedMeta:__newindex()
  101.     error("Attempt to modify a readonly table",2)
  102. end
  103.  
  104. local instance = {}
  105. register(instance,Instance)
  106. function instance.new(...)
  107.     return sandbox(Instance.new(unsandboxTuple(...)))
  108. end local function set(a,b,c) a[b] = c end
  109. function instance.wrap(obj)
  110.     local met,props,d = {},{},{}
  111.     function met:__newindex(key,val)
  112.         if props[key] then
  113.             d[key] = val return
  114.         end obj[key] = val
  115.     end met.__metatable = "Locked"
  116.     function met:__index(key)
  117.         if props[key] then
  118.             return d[key]
  119.         end return obj[key]
  120.     end
  121.     local res = setmetatable({},met)
  122.     FakeToReal[res] = FakeToReal[obj]
  123.     return res, props
  124. end setmetatable(instance,lockedMeta)
  125.  
  126. function _rawget(tab,key)
  127.     return rawget(FakeToReal[tab],key)
  128. end register(_rawget,rawget)
  129. function _rawset(tab,key,val)
  130.     return rawset(FakeToReal[tab],key,val)
  131. end register(_rawset,rawset)
  132.  
  133. local function Sandbox(script)
  134.     local env = {}
  135.     env.script = sandbox(script)
  136.     setmetatable(env,envMeta)
  137.     return env
  138. end
  139.  
  140.  
  141.  
  142.  
  143.  
  144. --[[ START EXAMPLE CODE ]]--
  145. local function test()
  146.     print("script =",script)
  147.     print(game,game.Name)
  148.     local p,props = Instance.new("Part",workspace)
  149.     print("----------------")
  150.    
  151.     -- Wrap instance in something we can play with
  152.     p,props = Instance.wrap(p)
  153.     -- And make sure we can edit the Banana property
  154.     props.Banana = true
  155.    
  156.     -- Using it with real instances should still work:
  157.     p.Parent = nil p.Parent = workspace
  158.     local val = Instance.new("ObjectValue")
  159.     val.Value = p print("val.Value =",val.Value)
  160.    
  161.     -- Now let's play with the Banana property
  162.     p.Banana = 123
  163.     print(p.Name,p.Banana)
  164.     print("Parent:",p.Parent)
  165.     p:Destroy()
  166.     print("Parent:",p.Parent)
  167.     print("----------------")
  168.    
  169.     -- We can also override properties, too lazy to fix this "issue"
  170.     props.Name = true
  171.     p.Name = "NotTheRealName"
  172.     print("Name stuff:",p,p.Name,p:GetFullName())
  173.     print("----------------")
  174.    
  175.     warn("This should print false and an error:")
  176.     print(pcall(function() return p.NonExistingStuff end))
  177.     warn("Next line should error too:")
  178.     print(pcall(function() p.NonExistingProperty = 123 end))
  179. end
  180.  
  181. setfenv(test,Sandbox(script))()
  182. --[[ END EXAMPLE CODE ]]--
  183.  
  184.  
  185.  
  186. return Sandbox
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement