What is the best way of creating player options?

I want to create options so the player can toggle between them (Disable textures, disable gun sounds, etc) but i have no almost no idea what is the best way to create them.

So far i have done some research on the forum and i found a post (I was going to link it but i didn´t found it) where it says that i should have a folder on each player with BoolValues or StringValues that represent each option and then toggle them with a RemoteEvent when the player presses a button on my settings Gui

Example:

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(plr)
	local plrSettings = Instance.new("Folder")
	plrSettings.Name = "PlrSettings"
	plrSettings.Parent = plr
	
	
	local textureToggle = Instance.new("BoolValue")
	textureToggle.Name = "TextureToggle"
	textureToggle.Parent = plrSettings
	
	local shadowToggle = Instance.new("BoolValue")
	shadowToggle.Name = "ShadowToggle"
	shadowToggle.Parent = plrSettings
	
	local muteGunSound = Instance.new("BoolValue")
	muteGunSound.Name = "MuteGunSound"
	muteGunSound.Parent = plrSettings
	
	local disableUsername = Instance.new("BoolValue")
	disableUsername.Name = "DisableUserName"
	disableUsername.Parent = plrSettings
end)

Then i should store all of the values on a DataStore, but im not to sure on how to do that.

Is this the best way of creating options? Or there are better ways to do this?

(Also sorry if i made some grammar mistakes, English is not my main languaje)

Hey man,

Using tables and datastoreservice would be your best move here, unless your consistently and regularly updating the settings (which I wouldn’t assume you are).

I’ll leave some example code below;

local PlayerService = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local SettingsDataStore = DataStoreService:GetDataStore("settings_storage") -- or whatever you would like the key to be, doesn't matter

--[[
    use :GetAsync & UpdateAsync to update player data
]]--

--[[
    Your table would be structured how you like, but I would do it as the same names:
]]

local base_user_settings = {
    textureToggle = false,
    shadowToggle = false,
    muteGunSound = false,
    disableUserName = false
}

PlayerService.PlayerAdded:Connect(function(player)
    local success, response = pcall(function()
        return SettingsDataStore:GetAsync(player.UserId)
    end)
    if not success then -- did the data store error
        warn(response)
    end
    if not response then -- if no values are currently stored then set it to your default settings
        response = base_user_settings
    end
    playerdata = response
    --[[
        to access these values, you can use either or below:
        playerdata["setting_name"]
        or
        playerdata.setting_name
    ]]
    --your code/changes you need to make to settings or just loading them

    -- once ur done, if you make any changes store it like this:
    local success, response = pcall(function()
        return SettingsDataStore:SetAsync(player.UserId, playerdata)
    end)
    if not success then
        warn(response)
    end
end)

--[[

note: pcall function just catches the error and doesnt allow it to stop your script from running

DataStores Documentation
pcall function documentation

I would suggest trying to write this yourself instead of copying it as it helps you learn. Best of luck man.

this code was not checked for errors as i wrote it in VS in a lua file so let me know if something doesnt work

4 Likes

Alr, i will check this out, thank you! I will mark out as the solution if it works

Okay, best of luck man. Docs are your best bet and if you run into any errors I’ll try my best to respond once I’m awake

1 Like

For now the texture changes for everyone becouse i have no idea on how i should do it only for the client, but that´s not a big problem, i think i kinda figured it out.

The biggest problem it that it doesent saves the player values, when i enter and i disable the textures and then i leave, when i come back all the textures are enabled, idk what is the problem, if you could provide some help it would be great.

Script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local DataStore = game:GetService("DataStoreService")

local settingsEvent = ReplicatedStorage.RemoteEvents.SettingsEvent
local plrModule = require(script.PlayerModule)

local settingsDataStore = DataStore:GetDataStore("plrsettings")
local sessionData = {}

--Base data
local usersettings = {
	textureToggle = false,
	shadowToggle = false,
	muteGunsound = false,
	disableUsername = false
}

Players.PlayerAdded:Connect(function(player)
	local success = nil
	local plrData = nil
	local attemp = 1
	
	--We are going to try to get the data 5 times in case it failed
	repeat
		success, plrData = pcall(function()
			return settingsDataStore:GetAsync(player.UserId)
		end)
		
		attemp += 1 
		if not success then
			warn(plrData)
			task.wait(2)
		end
	until success or attemp == 5
	
	--If there is not player data we are going to set the base one which is usersettings
	if not plrData then
		plrData = usersettings
	end
	
	--If there is no success we are going to kick the player
	if success then
		print("DataStore works!")
		sessionData[player.UserId] = plrData
	else
		player:Kick("Unable to get your settings data! if the error persists report to the dev team inmediatly")
	end
end)

--We are adding another function for when the player leaves
function plrIsLeaving(player)
	if sessionData[player.UserId] then
		local success = nil 
		local errorMsg = nil
		local attemp = 1
		
		repeat
			success, errorMsg = pcall(function()
				settingsDataStore:SetAsync(player.UserId, sessionData[player.UserId])
			end)
			
			attemp += 1
			if not success then
				warn(errorMsg)
				task.wait(2)
			end
		until success or attemp == 5
		
		if success then
			print("Data saved!")
		else
			warn("Unable to save settings")
		end
	end
end
Players.PlayerRemoving:Connect(plrIsLeaving)

--Another function in case of server shutdown
function serverShutdown()
	if RunService:IsStudio() then
		return
	end
	
	for i, player in pairs(Players:GetPlayers()) do
		task.spawn(function()
			plrIsLeaving(player)
		end)
	end
end
game:BindToClose(serverShutdown)

settingsEvent.OnServerEvent:Connect(function(plr, name)
	if name == "TexturesFrame" then
		local textureData = sessionData["textureToggle"]
		sessionData["textureToggle"] = not sessionData["textureToggle"]
		
		plrModule:TextureToggle(textureData)
	end
end)

Players.PlayerAdded:Connect(function()
	local textureData = sessionData["textureToggle"]
	plrModule:TextureToggle(textureData)
end)

LocalScript:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local gui = script.Parent
local buttonSettings = gui.OpenButton
local settingsFrame = gui.SettingsFrame
local scrollingFrame = settingsFrame.ScrollingFrame
local settingsEvent = ReplicatedStorage.RemoteEvents.SettingsEvent

buttonSettings.MouseButton1Click:Connect(function()
	settingsFrame.Visible = not settingsFrame.Visible
end)

for i, v in pairs(scrollingFrame:GetChildren()) do
	if v:IsA("Frame") then
		local button = v:FindFirstChild("ImageButton")
		local name = v.Name
		
		button.MouseButton1Click:Connect(function()
			settingsEvent:FireServer(name)
		end)
	end
end
Players.PlayerAdded:Connect(function()
	local textureData = sessionData["textureToggle"]
	plrModule:TextureToggle(textureData)
end)

Firstly you need sessionData[plr.UserID] to get the players settings. Right now you are trying to get a player userID “textureToggle”.
Secondly you are trying to pass a boolean into :TextureToggle(textureData) the problem is that this will pass a copy to that so the update will never be seen here (only tables are shared when passed). Instead do sessionData[plr.UserID][“textureToggle”] = not sessionData[plr.UserID][“textureToggle”] which does a toggle.

As for this, anything you do on the server effects every client, anything you do in a client script for the most part only affects the client (there are some exceptions). So you simply need to have the server send back to the client whether they should enable or disable textures and let the client do that. The client needs this anyways when you load the data otherwise your UI won’t be synced with the data from the server and will act like there is no data.

1 Like

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