local oldType = type; function type(v) local t = oldType(v); if t == 'table' then if ({pcall(getmetatable, v)})[2] == '__userdata' then t = 'userdata'; end; end; return t; end; function mewproxy(f, _func) local connections = { }; local function fire(...) for i, v in next, connections do v.fire(...); end; end; local function register(_t, _k, _v, typ) local function ftable(tbl) local tvals = { }; local errors = { edit = 'Please use the edit method to edit the value of an index'; add = 'Please use the add method to add indexes or values to table properties'; }; for k, v in next, tbl do if type(v) == 'table' then tvals[k] = ftable(v); else tvals[k] = v; end; tbl[k] = nil; end; local tfuncs = { add = function(self, k, v) if tvals[k] == nil then if type(v) == 'table' then tvals[k] = ftable(v); else tvals[k] = v; end; fire(k, v); else error(errors.edit, 0); end; end; edit = function(self, k, v) if tvals[k] ~= nil then if type(v) == 'table' then tvals[k] = ftable(v); else tvals[k] = v; end; fire(k, v); else error(errors.add, 0); end; end; } return setmetatable(tbl, { __index = function(t, k) if tvals[k] == false then return false; end; return tfuncs[k] or tvals[k] or nil; end; __newindex = function(t, k, v) if not tvals[k] then error(errors.add, 0); else error(errors.edit, 0); end; end; }); end; local meta, reg_f; local cval, readonly = _v, (typ == 'ro' or typ == 'readonly') and true or false; if type(cval) == 'table' then cval = ftable(cval); end; reg_f, meta = { __meta = function() return meta; end; __edit = function(v) if readonly == true then return error(string.format('Attempted to edit index %s (a %s/readonly value)', _k, type(cval)), 0); else fire(_k, v); cval = v; end; end; }, setmetatable({ }, { __index = function(t, k) return reg_f[k] or type(cval) == 'table' and cval[k] or error(string.format('Attempted to call %s (a nil value)', k), 0); end; __newindex = function(t, k, v) if type(cval) == 'table' then cval[k] = v; end; return error(string.format('Attempted to add an index to %s (a %s value)', _k, type(cval)), 0); end; __tostring = function() return (type(cval) == 'nil' and unpack({'nil', '__get'})) or (type(cval) ~= 'string' and type(cval) ~= 'number' and type(cval)) or cval; end; __metatable = true; }); if (typ == 'event') then readonly = true; reg_f.connect = function(self, func) assert(self == meta, 'Expected \':\' not \'.\' calling member function connect'); assert(type(func) == 'function', 'Bad argument #1 to \'connect\' (function expected, got ' .. type(func) .. ')'); local connection; local c_funcs = { disconnect = function(self) for i, v in next, connections do if connection == v then table.remove(connections, i) end end end; fire = cval; }; connection = setmetatable({ }, { __index = function(t, k) return k == 'disconnect' and c_funcs.disconnect or c_funcs[k](func) or error(string.format('Attempted to call %s (a nil value)', k), 0); end; __newindex = function(t, k, v) return error(string.format('Attempted to add an index to %s (a %s value)', _k, type(cval)), 0); end; __tostring = function() return _k; end; }); table.insert(connections, connection); return connection; end; end; _t[_k] = meta; end; if (f == true) then local _data, _meta; _data, _meta = { __getc = function() end; }, setmetatable({ }, { __index = function(t, k) return _data[k] or error(string.format('Attempted to call %s (a nil value)', k), 0); end; __newindex = function(t, k, v) if (({tostring(_data[k])})[2] == '__get' or _data[k] ~= nil) and type(_data[k]) ~= 'function' then _data[k].__edit(v); else return error('Attempted to add an index to a userdata value', 0); end; end; __tostring = function() return string.format('userdata: %s', string.match(tostring(_data), 'table: (%w+)')); end; __metatable = '__userdata'; }); --[[====================================================]]-- register(_data, 'Name', 'Proxy'); register(_data, 'NilVal', nil); register(_data, 'Table', {n = 1}); register(_data, 'ReadOnly', 'test', 'ro'); register(_data, 'Changed', function(k, v) return k, v; end, 'event'); --[[====================================================]]-- if (type(_func) == 'function') then _func(function(k, v) register(_data, k, v); end); end; return _meta; elseif (tostring(f) == 'userdata') then return f; end; end; --[[ Demo ]]-- local x = mewproxy(true, function(register) register('MEWVAR', 1, 'readonly'); end); print(x.MEWVAR); x.MEWVAR=2 print(x.MEWVAR); local event = x.Changed:connect(function(k, v) print(k, v); end); x.Table:add('t', { t = { t = { x = true; } } }); x.Table.t.t.t:edit('x', false);