Client turns a boolean into a cloned table?

this is some voodoo ahh functionality

basically,
i have settings right??
yeah and those settings get saved very nicely and stuff, except for ONE setting

the setting being Show Crosshair, for whatever reason the value of it is the settings table

setting it to true seems to fix it on the server, but for whatever reason
the client converts it into the settings table and i don’t know why


so we know that the client is the issue, but how is this possible??

i’m just going to drop you the code:

server side:

function InitializePlayerData(plr: Player)
	local totalKills = GetOrCreateAttribute(plr, "TotalKills", 0)
	local totalDeaths = GetOrCreateAttribute(plr, "TotalDeaths", 0)
	local totalCurrencyEarned = GetOrCreateAttribute(plr, "TotalCurrencyEarned", 0)
	local totalXpEarned = GetOrCreateAttribute(plr, "TotalXpEarned", 0)
	local currentLevel = GetOrCreateAttribute(plr, "CurrentLevel", 1)
	local currentWhisper = GetOrCreateAttribute(plr, "CurrentWhisper", 0) 
	-- 'Whisper' is basically a rebirth, but with an edgy name
	-- so think of 'Whisper' as 'Rebirth' if you find it easier

	local success, result = pcall(function()
		return playerDataStorage:GetAsync(plr.UserId)
	end)

	if not success then
		warn("Failed to fetch " .. plr.UserId .. "'s data!")
		warn("Error log: " .. result)

		result = nil
	end


	if not playerDataTable[plr.UserId] then
		-- Set data;
		playerDataTable[plr.UserId] = {
			TotalKills = totalKills,
			TotalDeaths = totalDeaths,
			TotalCurrencyEarned = totalCurrencyEarned,
			TotalXpEarned = totalXpEarned,
			CurrentLevel = currentLevel,
			CurrentWhisper = currentWhisper,
			Settings = {
				-- Default values
				["Field of View"] = 90, 
				["Classic Aim Down Sights"] = false,
				["Vitals GUI Color"] = Color3.fromRGB(255,255,255),
				["Weapon GUI Color"] = Color3.fromRGB(255,255,255),
				["Visible Viewmodel"] = true,
				["Show Crosshair"] = true,
				["First Person Tracers"] = true
			} 
		}
	end

	if result then
		playerDataTable[plr.UserId].TotalKills = result.TotalKills or totalKills
		playerDataTable[plr.UserId].TotalDeaths = result.TotalDeaths or totalDeaths
		playerDataTable[plr.UserId].TotalCurrencyEarned = result.TotalCurrencyEarned or totalCurrencyEarned
		playerDataTable[plr.UserId].TotalXpEarned = result.TotalXpEarned or totalXpEarned
		playerDataTable[plr.UserId].CurrentLevel = result.CurrentLevel or currentLevel
		playerDataTable[plr.UserId].CurrentWhisper = result.CurrentWhisper or currentWhisper
		
		local vitalsGuiColorDeserialized = Deserialize(result.Settings["Vitals GUI Color"])
		local weaponGuiColorDeserialized = Deserialize(result.Settings["Weapon GUI Color"])
				
		for setting, value in pairs(result.Settings) do
			playerDataTable[plr.UserId].Settings[setting] = value
		end
		
		warn(playerDataTable[plr.UserId].Settings["Show Crosshair"])
		
		result.Settings["Vitals GUI Color"] = vitalsGuiColorDeserialized
		result.Settings["Weapon GUI Color"] = weaponGuiColorDeserialized
	end
	
	returnPlayerSettings:FireClient(plr, playerDataTable[plr.UserId].Settings)
end

function OnSettingsReceived(plr: Player, setting: string, value: any)
	if not table.find(validSettings, setting) then plr:Kick("Don't do that") return end
	if cooldowns[plr.Name] then plr:Kick("That's very bad behavior") return nil end
	cooldowns[plr.Name] = true

	if not playerDataTable[plr.UserId] then
		-- If player data isn't found, then initialize it;
		InitializePlayerData(plr)
	end

	-- Update that value!
	playerDataTable[plr.UserId].Settings[setting] = value

	-- Some sort of warning that's here specifically for debugging :^)
	warn(plr.Name .. " changed " .. setting .. " to " .. tostring(value))
	warn("Current settings of " .. plr.Name .. " are: ")
	print(playerDataTable[plr.UserId].Settings)

	task.wait(0.1)
	cooldowns[plr.Name] = false
end

function SaveData()
	for userId, data in pairs(playerDataTable) do
		local success, result = pcall(function()
			local key = tostring(userId)
			
			-- These 2 values here are for serializing the color data
			-- because you can't store color3 values in datastores
			local vitalsGuiColor = data.Settings["Vitals GUI Color"]
			local weaponGuiColor = data.Settings["Weapon GUI Color"]
			
			local vitalsGuiColorSerialized = Serialize(vitalsGuiColor)
			local weaponGuiColorSerialized = Serialize(weaponGuiColor)

			playerDataStorage:UpdateAsync(key, function(oldData)
				oldData = oldData or {} -- No current data will instead initialize an empty table :^)

				local newData = {
					TotalKills = data.TotalKills,
					TotalDeaths = data.TotalDeaths,
					TotalCurrencyEarned = data.TotalCurrencyEarned,
					TotalXpEarned = data.TotalXpEarned,
					CurrentLevel = data.CurrentLevel,
					CurrentWhisper = data.CurrentWhisper,
					Settings = data.Settings
				}
				
				newData.Settings["Show Crosshair"] = true
				newData.Settings["Vitals GUI Color"] = Serialize(newData.Settings["Vitals GUI Color"])
				newData.Settings["Weapon GUI Color"] = Serialize(newData.Settings["Weapon GUI Color"])

				return newData
			end)
		end)

		if not success then
			warn("Failed to save " .. userId .. "'s data!")
			warn("Error information: ")
			warn(result)
			continue -- Skips to the next iteration so that print 
			-- below doesn't run 
		end

		print("Successfully saved data for " .. userId)
	end
end

client side

playerSettings.SettingChanged = function(setting: string, value: any)
	if cooldown then return end
	cooldown = true
	
	if setting == "Field of View" then
		-- This should hopefully work without issues
		if value > 110 then value = 110 end
		print("Field of view changed to: " .. value)
		
	elseif setting == "Classic Aim Down Sights" then
		-- Need to apply some sort of value here
		print("The value of " .. setting .. " is now ", value)
		
	elseif setting == "Vitals GUI Color" then
		-- Now we loop through the screen guis and find 'PlayerHUD'
		-- Indentations and nested for loops warning :(
		for _,element in plrGui:GetChildren() do
			if element.Name ~= "PlayerHUD" then continue end
			
			-- Then we loop through the descendants of PlayerHUD and
			-- Recolor the image labels to the color given
			for _, toRecolor in element:GetDescendants() do
				if not toRecolor:IsA("ImageLabel") then continue end
				
				toRecolor.ImageColor3 = value
			end
		end
		
	elseif setting == "Weapon GUI Color" then
		-- Same as in vitals GUI recoloring
		for _, element in plrGui:GetChildren() do
			if element.Name ~= "Weapons" then
				
				for _, toRecolor in element:GetDescendants() do
					if not toRecolor:IsA("ImageLabel") then continue end
					
					toRecolor.ImageColor3 = value
				end
			end
		end
		
	elseif setting == "Visible Viewmodel" then
		print("The value of " .. setting .. " is now ", value)
		
		local viewmodelsFolder = rStorage:WaitForChild("Viewmodels")
		
		if value == true then
			for _, basePart in viewmodelsFolder:GetDescendants() do
				if not basePart:IsA("BasePart") then continue end

				basePart.Transparency = 1
			end
			
		else -- If it's false instead
			for _, basePart in viewmodelsFolder:GetDescendants() do
				if not basePart:IsA("BasePart") then continue end
				
				basePart.Transparency = 0
			end
		end
		
	elseif setting == "Show Crosshair" then
		-- Same as in viewmodel and ads, some value
		print("The value of " .. setting .. " is now ", value)
		
	elseif setting == "First Person Tracers" then
		print("The value of " .. setting .. " is now ", value)
	end
	
	-- After the clusterbomb of elseif statements, it is time to
	-- send the setting and the value to the server
	sendPlayerSettings:FireServer(setting, value)
	task.wait(0.1)
	cooldown = false
end

local function InitializeSettings(data: any)	
	warn(playerSettings) -- show crosshair is true here
   for setting, value in pairs(data) do
		playerSettings:UpdateSetting(setting, data)
   end
end

returnPlayerSettings.OnClientEvent:Connect(InitializeSettings)
-- All of the values written in here are default values;

local playerSettings = {
	["Field of View"] = 90, 
	["Classic Aim Down Sights"] = false,
	["Vitals GUI Color"] = Color3.fromRGB(255,255,255),
	["Weapon GUI Color"] = Color3.fromRGB(255,255,255),
	["Visible Viewmodel"] = true,
	["Show Crosshair"] = true,
	["First Person Tracers"] = true,
	["Show Blood"] = true,
	["SettingChanged"] = nil :: ((string, any) -> (nil))? -- Actually a callback
	-- Thanks to that guy on the devforum for telling me this :^)
}

function playerSettings:GetSetting(name: string)
	return self[name]
end

function playerSettings:UpdateSetting(name: string, value: any)
	self[name] = value
	playerSettings.SettingChanged(name, value)
end

return playerSettings

this is the output:
image

the big table is printed on the client before initiating anything

but then for whatever reason it just gets set to a table??

image

I assume this is where you are trying to send it to the player. You are sending the Settings array in the FireClient thing, when you mean to do just a single entry in it, I believe.

Try replacing

playerDataTable[plr.UserId].Settings

with

playerDataTable[plr.UserId].Settings["Show Crosshair"]

and see if it fixes your issue

  1. Settings is a dictionary, not an array
    image

  2. i wanna send the entire settings, not just one entry (because that is very bad!!)

it’s the settings again! I knew this day would come…

ok so basically theres a few things you did here:

  1. You outputted the default settings, as shown in quotes 1 and 2 which is actually kind of misleading and probably confused u a lot with this issue

  2. In the loop of the settings (see quote 3) i think you meant to do this:

playerSettings:UpdateSetting(setting, value)
--instead of
playerSettings:UpdateSetting(setting, data)

because when u called that function u passed all of the settings instead of just the value of the current setting

MY GOAT FROM :uk: :heart: :heart:

can you help me with one more thingggggg??? :pleading_face:

for some strange reason, the gui colors that get passed are received as tables (even though they’re identified as color3 on server-side?

image

image

:frowning:

so first i thought it might be a problem with ur deserialise function but i looked at it again and it isnt (i spent ages trynna find that old chain of dms and posts :c)

anyway the issue is here

its all good up until the last two lines of the quote

what you’re doing is you’re overwriting the serialised value with the deserialised value inside the table of fetched data but it never gets changed in playerDataTable[player.UserId].Settings, and then down here:

you fire the data in the server settings table, which contains the serialised values, not the deserialised ones.

basically you can fix this by passing the server data settings table instead of the data store results one

1 Like

omg thnak you thank you thank you

thanks cutie pookie patootie
you have a special place in my heart

1 Like

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