Skip to content

Animation State Customizations

Peaches edited this page Feb 19, 2023 · 13 revisions

THIS PAGE IS FOR ARCHIVAL PURPOSES AND ANIMATION CUSTOMIZATIONS ARE NO LONGER USED IN XHUD

Using Animation-States for In-Game Customizations

A major development of Xhud is the implementation of an in-game customization menu, with very similar options to the more traditional / clunky #base customizations. This is accomplished by using the testhudanim command to call custom animations that manipulate the desired HUD elements to the customized state. Animation-state customization holds a few advantages and limitations compared to the traditional #base method, I'll discuss those and mitigation factors now to help you decide if this is something you should consider implementing.

Benefits Of Animation-State Customization:

  • More intuitive customization for the user.
  • Once setup, it can be easier for the developer to add customizations.
  • Full customization sets can be shared between users with simple drag+drop.
  • Only the desired customizations are actually run, allowing for more possible customizations without running into the load time or stuttering issues associated with #base customizations.

Limitations of Animation-State Customizations:

  • Can have a steeper initial learning curve for developers.
  • Resets with HUD reloads (hud_reloadscheme, toggling antialiasing, changing resolution, etc).
  • Cannot effect menus and other out of game elements. By definition we are limited to what animations can manipulate.
  • Animating elements that are manipulated by other animations requires special consideration.
  • The file that settings are saved to (we'll get into that) has a maximum size of 1 MB.
  • Customizations require sv_cheats 1, which can be done on the main menu without issue. This is hardly a limitation since #base requires more obtrusive measures...

Mitigation Measures:

  • Hopefully this wiki helps with the learning curve.
  • hud_reloadscheme can be aliased over to prevent accidental executions and handled with a alternative reload command, such as this functionally identical reload or toggle mat_aaquality. You can also add your trigger to load customizations after executing this command, though you will likely want to limit this to main menu due to the sv_cheats requisite.
  • A little bit of thought can overcome most cross-animation issues, generally as long as you are using two different animation types (eg. SetVisible+FGcolor | SetVisible+SetPos | etc). I have yet to actually be limited by this, though it is imaginable.
  • I've taken many steps to optimize the saving of settings, to the point where realistic estimates of how long it would take to fill the 1 MB file limit is around 7.5 years. So simply plan on pushing an update that changes the save file name every couple years.

Technical Details

How the animations manipulate elements is fairly simple and does not really require any trickery, the complexity in animation-state customizations comes from the saving and loading of customization settings, in such a way as to create an experience of persistent customizations for the user.

Setting Up Customizations

1. Firstly, I run a .cfg file at launch to apply the essential settings. I do this by adding exec xhud.cfg to valve.rc. I decided to run my commands after the execution of the user's autoexec, so that if I don't have any conflicts with user config settings and can override settings if needed.


2. As mentioned, we run xhud.cfg, which assigns creates a few blank or nullified aliases.

alias x_chatpos ""

alias x_chatpos_dump ""

The purpose of these commands is more clear in later stages, but to briefly lay out the terminology for what they do:
The alias x_chatpos is written over to contain a command for what customization is selected, so that when it is called at a later stage, we only run the commands that we want to run.
The alias x_chatpos_dump is assigned by the buttons in our customization menu and is responsible for writing the selected settings to a console log file.
The reason we nullify these aliases immediately so that when we save and load customizations by calling these aliases, if nothing has been assigned to these, they are registered as entirely blank as opposed to throwing "unknown command" errors into our saves/loads.


3. Next we assign the aliases for actually triggering the animations that apply our relevant customizations:

alias upperchat "testhudanim UpperChat; echo upper left chat loaded"
alias lowerchat "testhudanim LowerChat; echo lower left chat loaded"

If executed, these aliases use the testhudanim command to trigger the respective HUD animation events, which look like:

event UpperChat
{
  Animate HudChat    ypos   25    Linear 0.0 0.1
}
event LowerChat
{
  Animate HudChat    ypos   r210    Linear 0.0 0.1
}

4. The last aliases defined in xhud.cfg are very important to the whole process, as they are responsible for the nonvolatile storage of the customizations.

alias cpu "alias x_chatpos upperchat"
alias cpl "alias x_chatpos lowerchat"

These aliases are stored in a console log file, which has a maximum file size of 1 MB before it will stop working, which is why the aliases are as short as possible, at just 3 characters. These are also very important as they are responsible for reassigning the x_chatpos alias to the command to the desired customization option.
The reason we use x_chatpos as a middleman and don't directly tie these settings to customization options, is because we cannot clear the console log files, so we will run all the aliases stored in that file every time we call it, which would be substantially more resource intensive if it executed a bunch of animations instead of simply reassigning aliases.


5. xhud.cfg lastly calls the commands: exec xhud_customizations.txt and exec xhud_load which are responsible for loading saved settings. Before explaining how settings are loaded, I'd like to explain how settings are saved instead, as I think that will end up filling in some information gaps.


Saving Customizations

6. Before we actually save what settings are selected, we mark what customizations have been changed by using the menu bottoms themselves to assign the x_chatpos_dump commands. The relevant menu button commands look like:

"command" "engine lowerchat; alias x_chatpos_dump echo cpl"

For the lower chat position customization, and:

"command" "engine upperchat; alias x_chatpos_dump echo cpu"

For the upper chat position customization.
We assign these aliases directly from the menu buttons so that only customizations that have been changed will be written to the console log file, as a means very effective of memory optimization.
These buttons also directly trigger the alias that applies the customization and reports it to console, since we want these changes to take place when the user selects them.


7. Next we have the user specify to save these settings by selecting the "Save" button on our menu for two main purposes I'll get into. But the code for the save button looks like:

"command" "engine exec xhud_save; cl_mainmenu_safemode 0"

The first reason we require the user to specify to save the settings is another form of memory optimization. Rather than automatically saving settings when they are applied or every time the game is closed, we require the manual trigger of it so that only when the user is done will it be saved and only when the user has interacted with the menu will it be saved.
Second, the save button closes the menu (in this case I used main menu safemode to create the menu). This is a spam-protection measure, so as to prevent someone from unintentionally spamming the button for whatever reason, as they would have to be fairly deliberate in repeatedly opening the menu and selecting save to fill the console log file any notable amount.


8. Once the "Save" button has been pressed, the file xhud_save.cfg is executed and saves the selected customizations. The code for doing this:

con_timestamp 0
con_logfile cfg/xhud_customizations.txt
x_chatpos_dump
con_logfile ""

This file actually writes the applied settings to the console log file by firstly ensuring that there are no timestamps that would fill the file needlessly and create issues when loading the file, done via the command con_timestamp 0.
Then we define the log file we want to write these commands in, in this case: "xhud_customizations.txt"
Next we call the x_chatpos_dump alias, which prints whatever setting the user selected (cpu, cpl, or blank if nothing was selected but the user saved anyway). This is why in step 2 we nullified these aliases, as we do not want "unknown command" errors being written into the log file.
Finally, we stop writing to any console log file, so that no other commands make it into our log file.


Loading Customizations

9. As mentioned in the section explaining xhud.cfg, the process of loading saved settings is done firstly by executing xhud_customizations.txt, which is the file we saved our applied settings to. The file, once used, may look something like this:

cpl
cpu
cpu
cpl

Note the most recently saved setting is at the bottom of the file, and as such is executed last, which is important as that is what we want for the next steps in loading. In this case, though each of these lines would reassign x_chatpos, it would end on alias x_chatpos lowerchat.


10. Lastly, xhud.cfg executes xhud_load.cfg which looks something like:

sv_cheats 1

x_chatpos

This makes sure that we can run the testhudanim command by setting sv_cheats 1, then it 'scans' for settings to load by calling the x_chatpos command. This alias will either execute the alias responsible for actually running the animation events to apply the customization, or will result in a blank command if nothing was selected, because we nullified the alias in step 2.


File Overview

Assuming our files only contain chat position customizations.

hudanimations.txt

event UpperChat
{
  Animate HudChat    ypos   25    Linear 0.0 0.1
}
event LowerChat
{
  Animate HudChat    ypos   r210    Linear 0.0 0.1
}

valve.rc:

exec autoexec.cfg
exec xhud.cfg

xhud.cfg:

alias x_chatpos ""

alias x_chatpos_dump ""

alias upperchat "testhudanim UpperChat; echo upper left chat loaded"
alias lowerchat "testhudanim LowerChat; echo lower left chat loaded"

alias cpu "alias x_chatpos upperchat"
alias cpl "alias x_chatpos lowerchat"

exec xhud_customizations.txt
exec xhud_load

xhud_customizations.txt

...
...
cpl

xhud_load.cfg

sv_cheats 1

x_chatpos

mainmenuoverride.res

(Lower Chat Position Button)
"command" "engine lowerchat; alias x_chatpos_dump echo cpl"

(Upper Chat Position Button)
"command" "engine upperchat; alias x_chatpos_dump echo cpu"

(Save Button)
"command" "engine exec xhud_save; cl_mainmenu_safemode 0"

xhud_save.cfg

con_timestamp 0
con_logfile cfg/xhud_customizations.txt
x_chatpos_dump
con_logfile ""

Scaling

While this whole process can seem very complicated on the scale of a singular customization choice with 2 options, the nice part about it is that it remains virtually the same, regardless how many options you have.
For example, to add 4 different custom scoreboards to my HUD customization options, I do the same thing as my 2 chat position options, except this time with 4 and with appropriate names.
Scoreboard animations do require a slight modification the the animation events, requiring a seperate event for controlling the player lists and background. This is an extremely simple alteration to make and the scoreboard is the only element I have run into requiring it, but this is what that alteration looked like:

event 6v6Scoreboard
{
  Animate RedPlayerList     tall    101    Linear 0.0 0.1
  Animate BluePlayerList     tall   101    Linear 0.0 0.1
  RunEvent 6v6ScoreboardBG    0.0
}
event 6v6ScoreboardBG
{
  Animate ScoreboardMainBG    tall  144    Linear 0.0 0.1
  Animate ScoreboardMainBG    ypos    190    Linear 0.0 0.1
}

Then replicate that 3 more times for the 3 other options.