How to have a table viewable by both server and client

Now that I have more context, instead or using any remote events or functions at all, why not just load it all onto the server, and just render it all on the client? What I’m saying is that any blocks that are not in the viewport of the player will not get rendered, kind of like streaming enabled. There really isn’t a need for a table, because if the block got destroyed by the server, why would you have to render it anyway.

Instead of using these table thing, couldn’t just try other ways? Maybe you can render all the block in the mine in the server side, but limit the blocks player can see, for example up to 10 blocks to bottom (and then you update every 5 seconds).

Because if I were to load all the blocks into the server and there were say 100,000 blocks all with textures on I feel that would have some major performance implications, this system isn’t for a game as I said, its an efficiency contest so I really need to overkill with only loading in what NEEDS to be loaded.

What you can do is setup a table on the serverside, hook it up with a metatable through a proxy, and then each time that table’s values are changed you can hook it up to a RemoteEvent to send that table to the client.

To edit the table from the clientside you would just use a RemoteEvent to the server, do sanity checks and then edit the table, and if you setup your table correctly the table would have changed on the clientside.

If I were to add 5 values to the table say 4 times a second thats 20 remote calls / second which I feel is impractical given my use case.

You’re probably better of just using remotes then altering values on the server, and on request (through remote events or remote functions again) send back the value, remote functions would be more convenient here.

You can queue up remote calls then, if you really wish to. Realistically speaking there’s no real other efficient way (that I can think of) to do this, you could try using Instances but that would just be a headache.

The problem with that is roblox module scripts are really misleading, what looks like one module script in the explorer is actually 2, one exists on the client the other on the server, so if I were to update the module on the server, the only way I could get the data onto the client is through remote events.

I also only need the server to modify the module, the client only has to read it

1 Like

If you update a module script on the server, the changes are not replicated to the client

I have tried re-requiring it ever time I run the check however its still yielding the same result where the server and client’s versions of the module are completely out of sync. Modules contents are not replicated across the server-client boundary

How many blocks do you have in a world / is it infinite? What percentage of those blocks are viewable by the client? How is your position data stored?

The amount is infinite, blocks generate around you as you mine, Currently a maximum of around 200 blocks would be loaded in on the client and my position table is stored as example:

BlockData = {
[Y-Cordinate] = {
[X-Co-ordinate] = {[Z-Coordinate] = BlockTYPE}
}

}

Keep in mind im not using roblox co-ordinates, im ijust reprenting each block as 1x1x1 in terms of my positioning data

  1. You may want to research better data structures for voxel worlds – a whole table for each y- and x-coordinate block is going to eat your memory as the world expands. Especially since you’re using the dictionary form of lua tables. (edit: I was wrong, I think as long as the keys of the dictionary are contiguous and start at 1, they are stored as an array, not a hash table. Still, you would have one array per block, which will hurt things like caching, and possible GC and access time depending on how you use them.)
  2. 200 blocks is nothing to the server – send all 200 when the client logs in, and then have the client just send deltas to the server and vice-versa.
  3. … But honestly, I wouldn’t try to solve this problem. Replicating bricks and local changes to other clients is what ROBLOX is built to do. Why can’t you have the server place all the parts in workspace, throw on StreamingEnabled, and have their servers handle it? Then you can just send destroy/create events to the server and it will handle updating the view for everyone.

I really wouldn’t try to create a fully-fledged voxel engine in ROBLOX, since they’ve pretty much done all that work for you already!

edit: But if your heart is really set on it, here’s some links that might lead you to fun places. Again though, this isn’t really a simple problem :slight_smile:

2 Likes

Have a remote function under game.ReplicatedStorage called “retrieve”

--server

local r = game.ReplicatedStorage.retrieve

local t = {}
t["i"] = "value";

r.OnServerInvoke = function(_, ind) 
	return t[ind]
end

-- client
local get = game.ReplicatedStorage.retrieve
local t = {}
setmetatable(t, {__call = function(self, i) return get:InvokeServer(i) end})
print(t("i")) --> prints "value"

you could even use __index to give the illusion of having the table on the client as well but you can’t yield within a function bound to it so :man_shrugging:

Can’t think of other ways given changes in modules don’t replicate across the boundary, other than remote events (remote functions make it simpler in this case) .

1 Like

@nicemike40 and @Ra_f gave sage advice. You may also want to look at this from @Tomarty:

and take a look at this thread:

1 Like

That’s not storing for every block,

It’s storing the square for each Y cord, then the X for each crow then the Z for each individual block.

Besides how does this have any relevance to my issue

I’d appreciate it if you could also read my issue, I honestly don’t care how good roblox streaming is, the whole purpose of this is to make the most effieinct mining system possible

1 Like

Fire the table to the client using remote events, or all clients, fire again when it needs to be updated…

Sorry, I worded my first point imprecisely. Having a single table for each block is the issue. Tables are dynamically allocated, so that’s one allocation for every voxel. I was just suggesting you explore other options that might be faster – but you’re right, it’s probably premature optimization, so you can save that for if you run into issues later on if you like.

I was also saying that if you want to:

make the most [efficient] mining system possible

, you should utilize the tools ROBLOX has created, since you’re never going to match their speed or efficiency in Lua. The most efficient mining system is one that utilizes the network code native to ROBLOX.

I’d appreciate it if you could also read my issue

I did read your issue, and, unless I’m missing something, I and others have answered your question (in addition to suggesting a different approach).

To summarize what others in this thread have already said, though, if you still want to do it yourself:

  • Store your voxels in some kind of “chunk” data format (think minecraft chunks)
  • Clients request whole chunks at once with a RemoteFunction, and save a local copy of the table to render
  • Clients can update the server’s table with a RemoveEvent that takes (chunk, position) arguments or something
  • When the server receives that update, it can broadcast the change to other clients with a RemoteEvent and they can update their local copy of the chunks accordingly
  • The server can handle a few hundred bytes a second of data very easily, you shouldn’t need to worry about that – and you don’t need to resend the chunks every frame, just when a client moves far enough from their previous position, or logs in, or otherwise requests the data.
    • If you really want to, ratelimit the requests from clients (so they can only ask for x number of chunks per minute)

Kinda late, but I wanted to put this here just in case anybody else is looking for a solution. If you want to read a table that’s changed on the server and read on the client without constantly spamming remote events you can try this method.

Make a StringValue on the server then make the table in a server script. Convert that table to a string and set the StringValue’s Value to the table you just converted to a string. Then you can set an event on the client that checks for when the StringValue was changed. Once it detects the value is changed the client will convert it back to a table.

I haven’t tried this method myself so I don’t know if this would be more effective than using remotes.

Another method you could try is this:
The server script updates the table, which is located inside a modulescript, deleting the old one then creating a new one right after. In the local script, you can make it work via an update function:

local tbl = require(workspace:WaitForChild("TableData"))

workspace.ChildAdded:Connect(function(child) -- update the table on the client when the server script destroys the old one then makes a new one
    if child.Name == "TableData" and child:IsA("ModuleScript") then
        tbl = require(child)
    end
end)