Problem with syncing and shuffling player data in ModuleScript

Hi.

I created a game in which I keep the players’ data in a ModuleScript, namely module.data = {} (all examples will be given below).

The problem is that when a player enters the game, his data is loaded and placed in this module, but before that, some checks are made, for example, for the integrity or relevance of the variables in the table.

Server Script 1 :

> local ReplicatedStorage = game:GetService("ReplicatedStorage")
> local RequiredFunctions = require(script.Parent.ModuleScript)
> 
> local function CharacterAdded(character)
> 	local player = game.Players:GetPlayerFromCharacter(character)
> 	RequiredFunctions.GiveTools(player.UserId)
> end
> 
> local function PlayerAdded(player)
> 	RequiredFunctions.load(player.UserId)
> 	local remote_event = Instance.new("RemoteEvent",game.ReplicatedStorage.RemoteEvents)
> 	remote_event.Name = player.UserId
> 	player.CharacterAdded:Connect(CharacterAdded)
> end
> 
> local function PlayerRemoving(player)
> 	RequiredFunctions.save(player.UserId)
> 	if game.ReplicatedStorage.RemoteEvents:FindFirstChild(player.UserId) then
> 		game.ReplicatedStorage.RemoteEvents:FindFirstChild(player.UserId):Destroy()
> 	end
> end
> 
> game.Players.PlayerAdded:Connect(PlayerAdded)
> game.Players.PlayerRemoving:Connect(PlayerRemoving)

Module Script :

local module = {}
local DataStore = game:GetService("DataStoreService"):GetDataStore("DSQ004")
local ReplicatedData = game:GetService("ReplicatedStorage"):WaitForChild("ReplicatedData")
local defaultData = {

	Parts = 0,
	LeaveTime = math.floor(tick()),
	TimePlayed = 0,
	TimesJoined = 0,

	Name = "",
	Face = 144080495,
	Color = "29292f",
	Material = "SmoothPlastic",

	CarryingType = 0,
}

local VariablesToNil = {
	CarryingType = true,
}

module.data = {}

module.SetDataTable = function(id, data)
	for variable, value in pairs(defaultData) do
		if not data[variable] then
			data[variable] = value
		elseif typeof(value) ~= typeof(data[variable]) then
			data[variable] = value
		end
	end
	for variable, value in pairs(data) do
		if defaultData[variable] == nil then
			data[variable] = nil
		end
	end
	data.TimesJoined += 1
	module.data[id] = data
end

module.save = function(id, delete)
	local data = module.data[id] or defaultData
	for variable, value in pairs(data) do
		if VariablesToNil[variable] then
			data[variable] = nil
		end
	end
	data.LeaveTime = math.floor(tick())
	local success, error = pcall(function()
		DataStore:SetAsync(id, data)
	end)
	if not success then
		local retries = 0
		repeat
			task.wait(5)
			success, error = pcall(function()
				DataStore:SetAsync(tostring(id), data)
			end)
			retries += 1
		until success or retries >= 2
	end
	if delete == nil then
		module.data[id] = nil
	end
end

module.load = function(id)
	if module.data[id] then
		module.data[id] = nil
	end
	local function tryGetDataFromStore()
		local success, data = pcall(function()
			return DataStore:GetAsync(id)
		end)
		return success, data
	end
	local retries = 0
	local success, data = tryGetDataFromStore()
	while not success and retries < 2 do
		retries += 1
		success, data = tryGetDataFromStore()
	end
	if success then
		if data then
			module.SetDataTable(id, data)
		else
			module.SetDataTable(id, defaultData)
		end
		return true
	else
		local player = game:GetService("Players"):GetPlayerByUserId(id)
		if player then
			player:Kick()
		end
		return false
	end
end

return module

Server Script 2:

local ServerScriptService = game:GetService("ServerScriptService")
local MarketplaceService = game:GetService("MarketplaceService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local RequiredFunctions = require(script.Parent.ModuleScript) -- module script

local function GetPlayerData(id)
	return RequiredFunctions.data[id]
end

local functions2 = {
	["CarryingType"] = function(player, args)
		if GetPlayerData(player.UserId)then 
			GetPlayerData(player.UserId).CarryingType = args[2]
		end
	end
}

ReplicatedStorage.RemoteEvents.ChildAdded:Connect(function(remote)
	if remote:IsA("RemoteEvent") then
		remote.OnServerEvent:Connect(function(player,args)
			if player.UserId ~= tonumber(remote.Name) then return end
			if functions2[args[1]] then functions2[args[1]](player,args) end
		end)
	end
end)

coroutine.wrap(function()
	while true do
		task.wait(1)
		for _, player in ipairs(game:GetService("Players"):GetChildren()) do
			local data = RequiredFunctions.data[player.UserId]
			data.TimePlayed += 1
		end
	end
end)()

In general, the point is that any call for me happens like this:


local module = require(game.ServerScriptService.ModuleScript)

module.data["user id"] = {} -- "default data"

module.data["user id"].Parts += 1 -- example

if module.data["user id"].Parts == 1 then
	print("")
end

The point is that the data is mixed and, for example, when player 1 calls an event to change a variable in the table, this is replicated to the data of all players + they are superimposed. Let’s say 5 players logged in and now TimePlayed increases by 5 per second and not by 1 as required

3 Likes
local data = {}

local playerData = {}

function playerData.new(player)
local self = setmetatable({},playerData)
data[player]=self
return self
end

Like this, you can make individual data for every player.

1 Like

But how does this help with my code? In my module, everything is individual and tied to the player’s ID.

1 Like

I guess I don’t see what you’re stuck on

1 Like

Data from different players is replicated onto each other and added up…

1 Like

Yea, so you can use what I sent you to make a system where that won’t happen. You can just do

local data = {}

local playerData = {}

function playerData.new(player)
	local self = setmetatable({
		jointime = os.clock(),
		userId = player.UserId,
		isHappy = false
	},playerData)
	data[player]=self
	return self
end

for i,v in game.Players do
	playerData.new(v)
end

data[game.Players.Exercitus].isHappy = true
print(data[game.Players.ANONSOV].isHappy) -- false
print(data[game.Players.Exercitus].isHappy) -- true```
1 Like

Why won’t this happen in your system? Moreover, I wonder why this happens in my system. If I clearly separate the tables by player IDs

The problem is that whenever you use defaultdata, you’re not making a new copy of defaultdata. You’re using the exact same table.

So id = defaultData

Then you go and set some value for id. This means you’re setting it for defaultData, because it’s the original table.

Then you take a different id, and also set it to defaultData. But instead of getting the table you originally had, you get one that has been modified.

1 Like

But how can I use defaultdata without modification?
More precisely, how can I make it so that it doesn’t change?

Inheritance, or by using copies of the data. Lua Inheritance Tutorial - Complete Guide - GameDev Academy

I don’t know all the details, but before calling defaultData I created a copy of this variable and the “synchronization” problem disappeared

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