[RELEASED] Table.Changed custom function using Shadow tables

I’ve made a module which allows you to track when a property in a table is changed using Shadow tables

What is a Shadow table ?

A shadow table, also known as a proxy table simply put is a table that “acts” as it holds Data when in reality its “empty”. It basically uses metamethods to get the data that it doesn’t hold.

– Note this is a really plain and simple explanation, I recommend searching them up to get more in-depth explanation.

Additional info :

Whenever a new value is assigned a new thread is created.

How to use :

local ShadowTable = require(script:WaitForChild("ShadowTable"))

local Data = ShadowTable.New({Gold = 0})

Data.Changed:Connect(function(Index, Value)
	print(Index, Value)
end)

Data.Gold = 1235

In this case we change the value to 1235 and it will print out Gold, 1235.

Download the module down below, Thanks for reading

Download File
ShadowTable.rbxm (977 Bytes)

14 Likes

Hi, @Prexxo.

Very interesting module you got here thank you for sharing with us :+1:t2:

Would you kindly create a link to Source code (preferably Github and/or Pastebin) for people who want to read the source but don’t have any access to a PC or maybe want to contribute to the source

2 Likes

Sure, Currently only Table.Changed is possible, will add Table.Property.Changed sooner or later, Pastebin link: https://pastebin.com/gnUZhMhB, Feel free to share ; )

Why do you go for a non-Bindable event approach rather than with Bindable events? They’ll be easier to use and cover their entire set of functions and events.

By going with that approach, you will have no access to :Wait() or :Disconnect()

I think according to your code as well that it will set only one function when connecting due to overriding .Connection

This is because Bindables can’t serialize all data types, henceforth they can’t be sent.
ie: functions, Mixed-Tables, Gap-Arrays

This isn’t an issue, one can easy write an API to mimic ScriptSignals

What do you mean by serializing all data types? Though, you should add those extra functions that a Bindable event normally if you can easily mimic it.

local be = script.Parent
 
-- Define a simple function to connect
-- to the custom event
local function onEvent(...)
	print(...)
end
be.Event:Connect(onEvent)
 
-- These values CAN be sent when firing BindableEvents
be:Fire()           -- nil
be:Fire(25)         -- numbers
be:Fire("hello")    -- strings
be:Fire(true)       -- booleans
be:Fire("buy", 25)  -- multiple values are OK
be:Fire{1, 2, 3}    -- tables as arrays with no gaps
                      -- note the curly braces
be:Fire{            -- tables with string keys only
	hello = "world";
	goodbye = "world";
}
be:Fire{            -- tables with string keys
	point = {1, 2};   -- whose values are also valid
	point2 = {3, 4};
}
be:Fire{            -- tables as arrays
	{1, 2, 3};        -- whose values also are valid
	{hello = "world";};
}
 
-- These are some values you CANNOT send to/from BindableFunctions
be:Fire{1, nil, 3}  -- tables as arrays cannot have nil gaps
be:Fire{
	[{}] = "hello";   -- table keys can only be numbers OR strings
}
be:Fire{            -- tables keys cannot be BOTH numbers AND strings  
	[1] = "apple";
	hello = "world";
}

__

This is already made by multiple people;

2 Likes

Never knew about this guess I need to keep in touch with API stuff, thank you for the clarification. For my use, I never have to use mixed tables anyways so Bindable events would always work for my use but now I know to keep this in mind.

I did minimal testing on this, but I created a version of this module with a :GetPropertyChangedSignal implementation with a bit of a different coding style too:

ProxyTable.rbxm (1.7 KB)

The code I used to test it is:

local ProxyTable = require(path.to.ProxyTable)

local tabl = ProxyTable.new({ Gold = 0 })

tabl.Changed:Connect(print)
tabl:GetPropertyChangedSignal("Gold"):Connect(print)

tabl.Gold = 1235
--> Gold 1235 -- from `Changed`
--> 1235 -- from `GetPropertyChangedSignal`

I had an Event module sitting around, so I just parented it under the main module and implemented it for .Changed and cached :GetPropertyChangedSignal events. As for the Event module, it has a near-identical interface as a bindable event except for some necessary meta-data and :Fire being in the same scope. Otherwise, it has :Connect and :Wait methods.

1 Like

That is true although I can easily re create both functions u just mentioned. As for why I didnt use events is mainly to avoid networking

Did not know about them, could you please post the link that lead to their posts? Also I thought this was a fun little creation and wanted to share it, as well as seeing quite many people asking how to make something as Table.Changed so this is basically to give them the idea about it, you could also consider it a more efficient method than using binds as it doesn’t use networking to pass around changed Data.