Hello @5uphi,
First of all thank you for your contribution to the community.
I have been playing around with your framework and I have some questions:
- Global.ServerEvent
I have some local scripts on StarterCharacterScripts connected to RemoteEvents, but due to streaming those objects to whom the server scripts are attached are not existing yet.
This throws error
ReplicatedStorage.Global.Library.ServerEvent:24: attempt to index nil with ‘OnClientEvent’
Due to the fact that the constructor is waiting for the server to create the RemoteEvent
Global("ServerEvent", function<A...>(name, func)
local self = serverEvents[name]
if self then return self end
local remoteEvent = folder:WaitForChild(name) -- <-- HERE
if func then remoteEvent.OnClientEvent:Connect(func) end
local self = Global.Metatable({RemoteEvent = remoteEvent}, ServerEvent) :: Global.serverevent<A...>
serverEvents[name] = self
return self
end :: <A...>(name: string, func: (A...) -> ()?) -> Global.serverevent<A...>)
This is my code
Global.ServerEvent("Trigger", function(check)
if check == true then
-- do something
end
end)
How would you suggest to work around this? I’ve tried with the following but I’ve noticed it is only causing replication of the RemoteEvents, thus not solving the issue
local remoteEvent
if folder:FindFirstChild(name) then
remoteEvent = folder:WaitForChild(name,)
else
remoteEvent = Instance.new("RemoteEvent")
remoteEvent.Name = name
remoteEvent.Parent = folder
end
- PlayerData
I have been following your video with the example of creating global PlayerData, which I find really clever. I have connected that to the dataStore using your module, yet I am missing the saving events. I wanted to create an event to trigger every changes in PlayerData in order to update some custom UIs, so I’ve set up a module to create a proxy table that recursively gets updated in order to match the PlayerData structure (no matther the depth) and thanks to __newindex I’m capable to trigger the event. I’m using parentPath in order to get the path for the data structure.
This is the fuction in my custom module
local function wrap(value: any, dataChangedEvent, parentPath: string?)
if typeof(value) ~= "table" then
return value
end
local real = {}
for k, v in pairs(value) do
local childPath = parentPath and (parentPath .. "." .. k) or k
real[k] = wrap(v, dataChangedEvent, childPath)
end
local proxy = {
_path = parentPath,
}
setmetatable(proxy, {
__index = function(_, key)
return real[key]
end,
__newindex = function(_, key, newValue)
local oldValue = real[key]
local fullPath = parentPath and (parentPath .. "." .. key) or key
newValue = wrap(newValue, dataChangedEvent, fullPath)
if oldValue ~= newValue then
real[key] = newValue
dataChangedEvent:Fire(fullPath, oldValue, newValue)
else
real[key] = newValue
end
end,
__iter = function(_)
return next, real
end,
})
return proxy
end
function PlayerData.Create()
local dataChangedEvent = Global.Event()
local dataProxy = wrap({}, dataChangedEvent, nil)
return dataProxy, dataChangedEvent
end
In my PlayerObject script I’m setting
local proxy, dataChangedEvent = playerDataModule.Create()
self.Data = proxy
self.DataChanged = dataChangedEvent
Then, when successfully opening the dataStore I do the following
local function deepMerge(proxyTarget, source)
for key, newValue in pairs(source) do
local oldValue = proxyTarget[key]
if typeof(newValue) == "table" then
if typeof(oldValue) ~= "table" then
proxyTarget[key] = {}
oldValue = proxyTarget[key]
end
deepMerge(oldValue, newValue)
else
proxyTarget[key] = newValue
end
end
end
deepMerge(self.Data, dataStore.Value)
This way I can connect to the event when data are updated and send a Remote event to the client
local function toPlainTable(proxyOrValue)
if typeof(proxyOrValue) ~= "table" then
return proxyOrValue
end
local result = {}
for k, v in proxyOrValue do
result[k] = toPlainTable(v)
end
return result
end
self.DataChanged:Connect(function(key, oldValue, newValue)
local printableNew = typeof(newValue) == "table" and toPlainTable(newValue) or newValue
local printableOld = typeof(oldValue) == "table" and toPlainTable(oldValue) or oldValue
print((">> Data changed for %s | key=%s : %s => %s"):format(
self.Instance.Name,
tostring(key).split(key,".")[1],
tostring(printableOld),
tostring(printableNew)
))
Global.ClientEvent(tostring(key).split(key,".")[1]):Fire(self.Instance, key, newValue)
end)
Is there a way to integrate the wrap function directly in your Global framework instead of importing an external module?
Thanks a lot