Variables not updating on the client, even though their in replicated storage

So, I’ve been trying to make a movement system for my game, and to do that I made a module script to keep track of what the player is doing movement wise. The problem is that, when the attributes change in the module script (they’re not actually attributes, but I will refer to them as such for simplicity), it doesn’t update in a local script, even though the module script is in replicated storage. This problem doesn’t occur on the server though. I’ve looked all over the Developer Hub, but was unable to find a solution (btw, although the movement speed of the player is change on the client, the attributes are changed in a server script for convince. I figured that doing this would be fine, since the module script containing the attributes is in replicated storage, but I’m not so sure anymore).

Here is a break down of how the scripts involved work:

First, let me show you the module script responsible for keeping track of what the player is doing movement wise.

local CS = game:GetService("CollectionService")
local movement = {}

function Setdata(c)
-- function for setting all the attributes for all valid humanoids
	local h = c:FindFirstChild("Humanoid")
	if h then
		movement[c.Name] = {
			Dashing = false,
			CanDash = true,
			Sprinting = false,
			HasSprinted = false,
			CanSprint = true,
			SprintSpeed = 32,
			WalkSpeed = 16,
			JumpHeight = 7.2,
			JumpPower = 50
		}
	end
end

for _, c in pairs(workspace:GetChildren()) do
-- Sets attributes for humanoids already present in the workspace (dummies for example)
	Setdata(c)
end

workspace.ChildAdded:Connect(function(c)
-- Sets attributes for humanoids added into the workspace (when a npc or player joins or respawns)
	for i, v in pairs(CS:GetTags(c)) do
		if v == "Attack" then return end
	end
	Setdata(c)
end)

workspace.ChildRemoved:Connect(function(c)
 -- Resets attributes for dead humanoids (when a npc or player dies. Obviously.)
	local h = c:FindFirstChild("Humanoid")
	if h then
		movement[c] = nil
	end
end)

return movement

As I’ve stated before, this script is located on in replicated storage, so the client should have access to all the attributes for the corresponding humanoid.

Next is the script that handles all the inputs, which is seemingly the script where the error occurs.

UIS.InputBegan:Connect(function(input, gpe)
	if gpe then return end
	local MEH = require(game.ReplicatedStorage.StateHandlers.MovementEventsHandler)
	local MV = MEH[char.Name]
	if input.KeyCode == Enum.KeyCode.LeftControl and not MV.Sprinting then
		sprint:FireServer(char,true)
	elseif input.KeyCode == Enum.KeyCode.LeftControl and MV.Sprinting then
		sprint:FireServer(char,false)
	end 
end)

When you press LeftControl, it’s supposed to fire a remote event which will run this function:

function MovementSystem:SprintStart()
	MEH[self.char.Name].Sprinting = true
	event:FireClient(game.Players:GetPlayerFromCharacter(self.char),MEH[self.char.Name].SprintSpeed)
end

or this function:

function MovementSystem:SprintStop()
	MEH[self.char.Name].Sprinting = false
	event:FireClient(game.Players:GetPlayerFromCharacter(self.char),MEH[self.char.Name].WalkSpeed)
end

depending on whether you are running or not (btw the other remote event isn’t important, as it just changes the movement speed if the player on the client).

What actually happens is that you can start sprinting just fine, but you can’t stop, even if you press LeftControl again. After a bunch of testing, I realized that the attributes for the player don’t update on the client, but do on the sever. So when you start sprinting, the game thinks that you still aren’t sprinting, which causes you to keep sprinting even when you try to stop. I have no idea why this occurs because the model script is located in replicated storage, so it should update on the client, right? To be honest I’m not so sure anymore. The solution to this problem is probably really simple and I’m just being dumb, if that’s the case then sorry for wasting your time for something I should probably know lol.

Btw, for the people who are wondering why I’m doing the movement on the client and not the sever, I’m doing it because I’m already doing a lot, of stuff on the sever and I don’t want to do so much stuff on the server that lag will become a issue (although it probably will anyway). Also, I read somewhere that you should do all (if not most) of the movement related stuff on the client, also I read somewhere on the Developer Hub that a game called The Strongest Battleground does their movement on the client, and I want my game to have the same feel as that game, because of this, Unless it’s unreasonable or not possible, I would like the solution to include the movement being handled on the client, unless handling movement on the client is a dumb idea ofc.

Disclaimer:
Sorry for the most-likely-excessively-long post. This is my first post on the Developer Hub, so I apologize in advance for any grammatical errors in this post. Also, let me know if the way I formatted the post or my code was poor, and how I should format my next post and my code in general if so. These things are called posts, right?

1 Like

So, when you modify an module through the server, it’s not replicated automatically.

When you do moduleOrTable[key] = value, you are setting it as that value for the server’s memory, rather than modifying the module directly.

Only the source of an module replicates to the client, not the memory content of it. This means that both sides (server-side and players, clients) will have an module with different values, if they have been modified.

Automatic replication for tables (modules) is not possible, but you can instead create some workarounds it:

  1. Creating an :SetValue() function for the table (module):
    This function should be passing the modified property and new values to a remote event which then registers the change on the client-side. It acts as an wrapper: Any changes that don’t pass through it will not be detected, which may cause desynchronizations.

  2. Using __newindex metamethod:
    This method is a little bit advanced: It requires some understanding of how metatables and their metamethods work. The function for the metamethod would be similar to the SetValue function, but instead, it would be repllicating 100% of changes in properties. Programming in Lua : 13.4.2

4 Likes

If a value inside the module script updates on the server the changes will never be visible on the client

You can see it if you create a module script in replicated storage:

local vals = {1,2,3}
return vals

LocalScript:

task.wait(3)

local vals = require(game:GetService("ReplicatedStorage").ModuleScript)

print("client: ")
for i in vals do
	print(vals[i])
end

And server script:

task.wait(1)

local vals = require(game:GetService("ReplicatedStorage").ModuleScript)
vals = {4, 5, 6}
print("server: ")
for i in vals do
	print(vals[i])
end

The output will be:

server:
4
5
6
client:
1
2
3

3 Likes

Thank you for a solution! It worked like a charm! :grinning:

3 Likes

Thanks for the information! Your response is much appreciated. :grinning:

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.