Generalised per-resource user setting API

I think I’ve suggested this via other communication channels at least once before but it’s probably better to make a more formal post. Anyways, while the client-side kvs is a great place for storing user settings, resources are currently left to implement their own UI for allowing users to actually change settings.

Like with resource key mappings, a resource should be able to expose “settings” which can be changed via pause menu. Each resource that registers settings can get their own setting category (under “Rockstar Editor” settings) and hopefully that pause menu column supports scrolling for a server with many resources that register settings :’)

For ease of implementation, setting values could be saved in resource kvs and registered at runtime (like key mappings) by resources. Resources should be able to register “change handlers” (like they can for state bags) so they don’t need to poll setting storage for updates.

The pause menu already supports selecting from a set of values, numeric ranges and could support arbitrary input a with a “hack” that opens the input prompt on selection of the setting. That’ll cover the majority of settable things a resource could really need and the API could also allow for settings to be set as “disabled” to indicate settings that are constrained by other settings.

Here is an example usage of how I envision the concept but changes should certainly be made here to make it actually workable.

RegisterResourceSetting("setting-key", "Example Setting", {
	-- "select", "range" or "input"
	type = "select",

	-- used by the "select" type
	allowed_values = {
		["Displayed Value"] = "stored-value",
		-- etc. should require more than one value though :P
	},

	-- used by the "range" type
	-- min = 0,
	-- max = 5,
	-- step = 0.5,

	-- used by the "input" type
	--prompt = "" -- optional, defaults to something like "New value for Example Setting"

	-- used for the "Restore Defaults" button present in every setting category
	default = "stored-value",

}, 69 --[[optional setting sort value. defaults to 0]])

-- settings with a greater sort value appear above lesser sort values
-- settings with an equal sort value are sorted alphabetically by their display name

-- long name, perhaps there's something better to name this?
RegisterResourceSettingChangeHandler("setting-key", function(new_value, old_value)
	print("the example setting was changed to: "..new_value)
	-- possibly allow the change to be rejected?
end)


-- later in the resource...

-- get the value of the example setting
local value = GetResourceKvpString("user-settings:setting-key")
print("the example setting is: "..value)

-- should print "the example setting is: stored-value" even if the user hasn't touched 
-- the setting yet. an already existing value however shouldn't be overriden unless 
-- done by the user.

-- select type settings with set values that don't map to allowed_values should 
-- display as "invalid ({set value})" or so.

-- how to handle non-matching data types (a string stored in the key for a range)
-- i'm not too sure on, perhaps show the warning triangle until the value is changed
-- at least once?

-- example setting can't be changed for the next 5 seconds
SetResourceSettingEnabled("setting-key", false)
Citizen.SetTimeout(5000, function()
	-- okay, you can change it again!
	SetResourceSettingEnabled("setting-key", true)
end)

Obviously, the pause menu doesn’t have to be used here, it would just make the functionality feel well integrated. The general intent though is to enable a single place for all user config of resources, managed by the client, shared between servers.

4 Likes

Scoped convars, maybe?

Yeah that would work perfectly fine too, better even!
One in “developer mode” can do manual changes quickly via console and this follows the behaviour seen in most games where convars are used for user settings.