Thread Tools Display Modes
02/16/22, 12:49 AM   #1
Messajah
AddOn Author - Click to view addons
Join Date: Feb 2022
Posts: 11
Arrow Modifying built-in game settings via addon, such as toggling Scrolling Combat Text...

I've been searching the forums and didn't find any results regarding how to modify built-in game settings.


While looking at the API txt docs:
https://wiki.esoui.com/APIVersion#live_API_version

I found the following Constant:

Code:
h5. CombatSetting
* COMBAT_SETTING_SCROLLING_COMBAT_TEXT_ENABLED
However, that constant is literally just the number 0, and seemed useless at first.


I then noticed that the "Documents/Elder Scrolls Online/live/UserSettings.txt" seemed to contain all of the game's built-in settings. One of the lines in that file says: SET ScrollingCombatTextEnabled "1"


I realized how much that text file looks like World of Warcraft, where I used to develop addons... so let's just search for "cvar" in the API text file (that's how you'd change a setting in WoW)... and... hmm... voila:

Code:
h2. Game API
* GetCVar(*string* _CVarName_)
** _Returns:_ *string* _value_

* SetCVar(*string* _CVarName_, *string* _value_)

I decided to try the "WoW programming style" by simply setting the CVar like this:

Code:
SetCVar("ScrollingCombatTextEnabled", "1")
I just tried it out and it seemed to work. Toggling it between 0/1 changes the setting. And just like in WoW, I can see that ESO's CVars only accept string-type values (even floats would have to be written as "1.250000" etc).


After a while, I noticed that UserSettings.txt is very small and doesn't contain the majority of settings. So after some more investigation, I found the "SetSetting()" API which takes a "settings category" and "setting" variable along with a value. It stores the vast majority of the settings on the ZOS server (only a few things are stored locally instead, such as graphics settings). Usage is as follows:

Code:
* SetSetting(*[SettingSystemType|#SettingSystemType]* _system_, *integer* _settingId_, *string* _value_, *[SetOptions|#SetOptions]* _setOptions_)

* ApplySettings()

* RefreshSettings()

* GetSetting(*[SettingSystemType|#SettingSystemType]* _system_, *integer* _settingId_)
** _Returns:_ *string* _value_

* GetSetting_Bool(*[SettingSystemType|#SettingSystemType]* _system_, *integer* _settingId_)
** _Returns:_ *bool* _value_

* IsSettingDeferred(*[SettingSystemType|#SettingSystemType]* _system_, *integer* _settingId_)
** _Returns:_ *bool* _isDeferred_

* IsDeferredSettingLoading(*[SettingSystemType|#SettingSystemType]* _system_, *integer* _settingId_)
** _Returns:_ *bool* _isLoaded_

* IsDeferredSettingLoaded(*[SettingSystemType|#SettingSystemType]* _system_, *integer* _settingId_)
** _Returns:_ *bool* _isLoaded_

* RequestLoadDeferredSetting(*[SettingSystemType|#SettingSystemType]* _system_, *integer* _settingId_)
You just have to look up SettingSystemType (settings category) in the API txt, then also find the corresponding constant for the setting you want to change. You don't have to provide the weird final parameter. I tried the following, which successfully changed the 1st person FOV:

Code:
/script d(SetSetting(SETTING_TYPE_CAMERA, CAMERA_SETTING_FIRST_PERSON_FIELD_OF_VIEW, 80))
So I decided to try the SetSetting technique for the "scrolling combat text" CVar:

Code:
/script d(SetSetting(SETTING_TYPE_COMBAT, COMBAT_SETTING_SCROLLING_COMBAT_TEXT_ENABLED, "0"))
/script d(GetSetting(SETTING_TYPE_COMBAT, COMBAT_SETTING_SCROLLING_COMBAT_TEXT_ENABLED))
/script d(GetCVar("ScrollingCombatTextEnabled"))
/script d(SetSetting(SETTING_TYPE_COMBAT, COMBAT_SETTING_SCROLLING_COMBAT_TEXT_ENABLED, "1"))
/script d(GetSetting(SETTING_TYPE_COMBAT, COMBAT_SETTING_SCROLLING_COMBAT_TEXT_ENABLED))
/script d(GetCVar("ScrollingCombatTextEnabled"))
And guess what? SetSetting instantly updates the CVar. And in fact vice versa, if you SetCVar it changes the GetSetting result. It kinda seems like GetSetting/SetSetting is a Lua function they've written which wraps around both GetCVar/SetCVar (only when settings are also stored in CVar of course), in addition to communicating with their server backend storage method (so that settings sync to all computers you play on, which is the primary purpose of their server-side settings system).

I also managed to find a great 2016 post by a ZOS employee who explains that SetSetting basically uploads most of its settings to the server. So if you change the local settings directly via SetCVar instead of using SetSetting then you most likely won't sync the change to their server. Therefore, always use SetSetting when the thing you want to change is available there.

The ZOS developer's post also revealed that there is a command to force the game to upload all settings changes immediately, and he also described ApplySettings() which you need to call if you do any disruptive graphics changes:
https://www.esoui.com/forums/showpos...3&postcount=12

Originally Posted by ZOS_ChipHilseberg View Post
Here is how the settings system works. When a setting is changed it is cached off in a map on the client side. Every 1.5 seconds the client will pick a setting out of the map and send it to the server. This is done to prevent hitting the message rate limit when the player is quickly rotating through settings (like holding left on the thumb stick in the gamepad options for a horizontal list selector). The cache can be flushed manually by calling SendAllCachedSettingMessages() and it is also flushed automatically when the player changes zones or logs off. However, if it sends so many options updates that the message rate limit is hit, some of them can be lost.

ApplySettings() exists because some options changes (like graphics settings) are very disruptive when they are changed, sometimes requiring a reload. So they don't get put into effect until apply is called.
When he speaks about "every 1.5 seconds, one setting is synced to the server to avoid overloading the server and losing changes", he talks about the intended usage of the settings system: The player is in the settings GUI and changes something. The game then waits 1.5 seconds and then syncs the change to the server. Since most people probably take at least a second before they modify something else, this algorithm works perfectly and most changes will be have finished syncing before the player has even closed the settings GUI. If you change zone (see a loading screen) or logoff, then the game flushes all remaining cached settings modifications to the server.

Since only "1 modified setting is uploaded every 1.5 seconds" (meaning that 10 modified settings will take 15 seconds to sync in the background), you may think that this knowledge sounds relevant for addon authors if you algorithmically change a LOT of settings at once. But beware of his warning that flushing all changes can lead to lost settings due to server messaging overload, so you shouldn't simply flush them with the command he mentioned (don't use that). My recommendation for the SAFEST technique is to never manually flush and to let the game deal with syncing all your changes in the background while the user plays the game. If the player zones/logs off, then any remaining settings will be synced too.



It was also good to learn that most settings that you can change in the game this way will take effect immediately if you simply call SetSetting() directly, without any need to end with ApplySettings(). But some disruptive things (such as certain graphics quality or GUI scaling settings) require you to force the game to apply the change. So think about whether you need ApplySettings or not. Most of the time you probably won't need it. But if you're changing anything visual/graphical, then you should use it just to be sure it's applied.


Another very important thing I've just discovered, is that toggles (on/off) are always "1" or "0" values. But whenever an in-game setting has "multiple choices" (such as a dropdown menu), then you MUST look up the actual Constants representing those choices (do NOT hardcode "1" etc). Here's an example of properly setting a dropdown to the "crown store" choice:

Code:
/script d(SetSetting(SETTING_TYPE_IN_WORLD, IN_WORLD_UI_SETTING_DEFAULT_SOUL_GEM, DEFAULT_SOUL_GEM_CHOICE_CROWN)


It's also helpful to investigate the current values of the setting before you begin to modify it yourself. The returned type is ALWAYS a "string", but the meaning of the value MUST be carefully investigated by you before you modify anything. For example:

Code:
-- WARNING: This returns a number such as "1" but it's actually the value of a constant from DEFAULT_SOUL_GEM_CHOICE_*

/script d(GetSetting(SETTING_TYPE_IN_WORLD, IN_WORLD_UI_SETTING_DEFAULT_SOUL_GEM))


Lastly, keep in mind that the SetSetting API can't change certain hidden settings in the game. There are some SECRET SETTINGS that ONLY exists as local CVar without any other APIs, such as SetCVar("SkipPregameVideos", "1"), which will disable the game engine advertisement videos when the game starts up. There are many other secret/internal engine CVars, such as "MouseRawInput" and "MouseSmoothing". All of them can be found in UserSettings.txt, but beware that many things in there are actually set/synced via the SetSetting API, so always look for a corresponding SetSetting possibility first.


There are also certain in-game settings GUI things that you CANNOT modify via SetSettings or SetCVar. One example of that is the chat size, which instead uses DEDICATED FUNCTIONS:

Code:
* GetChatFontSize()
** _Returns:_ *integer* _fontSize_

* SetChatFontSize(*integer* _fontSize_)

* GetGamepadChatFontSize()
** _Returns:_ *integer* _gamepadFontSize_

* SetGamepadChatFontSize(*integer* _gamepadFontSize_)

* ResetChatFontSizeToDefault()


-- IMPORTANT SIDENOTE if anyone tries to use those APIs:
-- They only apply the change after you /reloadui.
-- There's probably some other "refresh all chat tabs
-- immediately" API, but I can't find it.


Another example is the chat colors, which also use a DIFFERENT API:

Code:
* GetChatCategoryColor(*[ChatChannelCategories|#ChatChannelCategories]* _category_)
** _Returns:_ *number* _red_, *number* _green_, *number* _blue_

* SetChatCategoryColor(*[ChatChannelCategories|#ChatChannelCategories]* _category_, *number* _red_, *number* _green_, *number* _blue_)

* ResetChatCategoryColorToDefault(*[ChatChannelCategories|#ChatChannelCategories]* _category_)



-- Example usage:

-- Returns a tuple with three numbers (floats).
-- /script d(GetChatCategoryColor(CHAT_CATEGORY_GUILD_1))

-- Set the color of guild1 (r, g, b). Takes effect immediately.
-- /script d(SetChatCategoryColor(CHAT_CATEGORY_GUILD_1, 0.8, 0.2, 0.3))


The only remaining question is... How do we sum up all this and figure out the best way of changing settings in Eso? From what I can see, it's as follows:

- SetSetting: THIS seems like the best way to change the game's settings. It seems to be able to change any setting, it syncs the changes to their server, and it uses the correct settings storage API (local CVar and/or server) internally. Always carefully investigate the valid/correct internal values (or constants) for each setting before you modify anything. You may have to manually trigger ApplySettings() if you change graphics or GUI scale settings (basically, anything that the game classifies as "disruptive changes" requires ApplySettings()). You should never manually force the server sync (since that could lead to lost changes if you send too many at once, and the server will kick you due to "message spam"). Lastly, we can be grateful that it seems like all of these settings API functions are public (not protected/private).

- SetCVar: Probably not synced to the server, and most likely only safe/good to use for secret, completely local settings such as "SkipPregameVideos". If you use it to modify some CVar that is actually available as a SetSetting, then your changes MAY PERHAPS not sync to the server (I haven't tested that to be sure, but either way it's just silly to SetCVar something that already exists as SetSetting so I won't research this deeper).

- If you want to READ a CVar, use GetCVar.

- If you want to READ a setting, use GetSetting, which always returns a string (no matter which data is stored in the setting). If it's a simple on/off setting, then its string value is usually the string "1" (on) and "0" (off). You can then simplify your code by using GetSetting_Bool instead, which returns true/false instead so that you can do "if GetSetting_Bool() then" instead of "if GetSetting() == "1"".

- In a few situations, such as chat font size and chat colors, you need to use dedicated functions for that (such as the aforementioned GetChatFontSize / SetChatFontSize, and GetChatCategoryColor / SetChatCategoryColor).

- ALWAYS search in the API txt reference/documentation file for the most recent game client (see the 1st link at the top of this post). Be very careful that you find the correct setting-type, setting-value (especially when it's a dropdown choice), or dedicated functions such as SetChatFontSize. And always do testing by reading the value via something like "/script d(Get.... that value)" while manually changing the settings in-game, to verify that you've found the correct setting before you write any code, otherwise you may corrupt people's unrelated settings or break the settings during future game updates.



PS: It's amazing how closely they've copied the WoW API. I love it. It feels very familiar. They were clever to do so, since it allows ex-WoW developers to extend ESO!

Last edited by Messajah : 02/16/22 at 02:38 PM.
  Reply With Quote
02/16/22, 02:55 AM   #2
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
Thank you very much for all of this info!
Most of it was known to me already but I also learned about ApplySettings that way.
We also run a Wiki (linked at the top) where this info would make sense to be added at the examples/tutorials section at the top right.
I've added your thread link there: https://wiki.esoui.com/How_to_change_ingame_settings

As addition there is a GetSettingsBool API function as often settings are just on/off. It eases the toggling as you do not need to change the normally returned string values 1 or 0 manually in your code for your usage like

If settingVar then (compared to if settingVar == "1" then).

I've moved your thread to the tutorials and info forum.


btw:
SetCVar also is used to directly change the client's language (no videos or audio! This needs to be changed in the ESO launcher settings AND downloads several GB then of video and audio files) directly to supported languages like de, en, es (next chapter, not yet on live server!), fr, ru and jp (only special Japanese client!)

Code:
/script SetCVar("language.2", "fr") --Change to French and reload the UI
This will be remembered after logout, so it is written to the UserSettings.xt file, but as you correctly said: The language is not stored at the server.
Settings of the ingame settings menus (except AddOns!) and controls/keybindings are stored at the server (~200 max keybinds per character).

All other settings like addons or even ZOs settings like "Include banked items at crafting table" are stored in the local SavedVariables folder. ZOs settingsa re stored there in ZO_*.lua files.

Last edited by Baertram : 02/16/22 at 08:43 AM.
  Reply With Quote
02/16/22, 09:30 AM   #3
Messajah
AddOn Author - Click to view addons
Join Date: Feb 2022
Posts: 11
Originally Posted by Baertram View Post
We also run a Wiki (linked at the top) where this info would make sense to be added at the examples/tutorials section at the top right.
I've added your thread link there: https://wiki.esoui.com/How_to_change_ingame_settings
Originally Posted by Baertram View Post
I've moved your thread to the tutorials and info forum.
Thanks a lot for the vote of confidence! Great job making a wiki page so quickly! I've appended some more info to the wiki too. It looks good now and has the most important overview of the situation, and the deeper info is here in this thread. I also rewrote/extended some explanations in this thread since it's now a "tutorial" for people so I want the information be easily understandable.

Thanks again. Take care!
  Reply With Quote

ESOUI » Developer Discussions » Tutorials & Other Helpful Info » Modifying built-in game settings via addon, such as toggling Scrolling Combat Text...

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off