I am currently working on making a simple Datastore module. I was attempting to create a system through which a localscript could call the “Save” function, and their data would be sent through a RemoteFunction which would invoke the same module on the server side so it could save the data.
code:
function Datastore.Save(key, dataName, data)
if key and dataName and data then
if RS:IsServer() then
print("Save is running on the server")
local cachedData = cache[key]
cachedData[dataName] = data
print(dataName)
print(data)
return true
elseif RS:IsClient() then
print("Save is running on the client")
local SE = Events:WaitForChild("Save")
local s = SE:InvokeServer(key, dataName, data)
return s
end
else
return false
end
end
if RS:IsServer() then
Events:WaitForChild("Save").OnServerInvoke = Datastore.Save()
Events:WaitForChild("Load").OnServerInvoke = Datastore.Load()
end
For context, ‘RS’ is the RunService, and the module is sitting in ReplicatedStorage.
The Problem:
When I try to run the “Save” function from the client I get this error: tables cannot be cyclic - Client - Datastore:33
I really hope there is a solution to this so that I can still allow the client to be able to run the ‘Save’ function. If that’s not possible, it’s fine, I can find another way to do it.
Yes, it fires a function from the client which when received on the server performs the action.
It’s all within the same function using “Runservice:IsServer()” and “Runservice:IsClient”
There are certain limits to what can be transfered within bindable/remoteEvents. I think the data parameter has a reference to itself (its metatable’s __index = data). Which is not allowed.
Also, you can only have table arrays in events. It’s just a harsh limitation
Limitations
Subscription
An event can only be subscribed to by one other script at a time. When a second script subscribes to an already subscribed event, the first script will be unsubscribed.
Parameters
If a Table is passed as an argument to a BindableEvent it must be an array without missing entries or have string keys, not a mixture, or else the string keys will be lost. Source: BindableEvent (roblox.com)
That makes sense. I had forgotten that the RemoteFunction also passed through what fired the function, which is most likely being passed as the module.
Also, bindableFunctions have even more restrictions
Limitations
Invocations will yield until the corresponding callback is found. If the callback was never set, the script that invokes it will not resume execution.
Subscription Only one function can be bound to BindableFunction/Invoke at a time. If you assign multiple functions, only the last one assigned will be used.
Parameter Limitations
Any type of Roblox object such as an Enumeration, Instance , or userdata can be passed as a parameter when a RemoteEvent is fired or a RemoteFunction invoked. Lua types such as numbers, strings, and booleans can also be passed, although there are some limitations on how data can be passed.
Mixed Tables
Avoid passing a mixed table (some values indexed by number and others by key), as only the data indexed by number will be passed . For example, when the server receives the colorData table illustrated below, it will only see indices 1 and 2 containing "Blue" and "Yellow" while the other data will be lost in the transfer. Note, however, that sub-tables do not need to be indexed in the same way as their parent — in other words, as long as each individual sub-table is indexed with the same type, all of the data will be preserved.
Non-String Indices
If any indices of a passed table are non-string type ( Instance , userdata, function, another table, etc.), those indices will be converted to a string.
local colorData = {}
colorData[1] = "Blue"
colorData[2] = "Yellow"
colorData["Color1"] = "Green"
colorData["Color2"] = "Red"
-- Table with two key-indexed sub-tables
local playerData = {}
playerData["CharData"] = {
-- All children indexed by key
CharName = "Diva Dragonslayer",
CharClass = "Knight"
}
playerData["Inventory"] = {
-- All children numerically indexed
"Sword",
"Bow",
"Rope"
}```
#### Functions
Functions passed as parameters will not be replicated, therefore making it impossible to use these objects to pass functions between scripts.
Okay I tried it and got the same error. I don’t know what the cause could be. Maybe it somehow thinks it could turn into an infinite loop. I don’t really know a lot about this stuff, so thats why I came here.
I mean, it isn’t the best solution, but you could try serializing the table to string via tostring and calling loadstring on it from the server.
Note: You will have to enable LoadStringEnabled in ServerScriptService
That stops the code from erroring, but the system still doesn’t work, so there may be a problem with the way that I am trying to activate the function now. The function is not fired on the server. I’m very new to Module scripts so I may just be doing it wrong:
probably u have a module script A refrencing module script B and module script B is refrencing modules script A creating an infinite loop. U should make one module that references all modules to fix this.
I think I could still concatenate all of the values and seperate them with commas. After that I could do string.split(), right? That would have a similar effect?