-
-
Notifications
You must be signed in to change notification settings - Fork 6
Animation State 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.
- 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.
- 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...
- 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 ortoggle 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.
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.
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.
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.
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.
Assuming our files only contain chat position customizations.
event UpperChat
{
Animate HudChat ypos 25 Linear 0.0 0.1
}
event LowerChat
{
Animate HudChat ypos r210 Linear 0.0 0.1
}
exec autoexec.cfg
exec 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
...
...
cpl
sv_cheats 1
x_chatpos
(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"
con_timestamp 0
con_logfile cfg/xhud_customizations.txt
x_chatpos_dump
con_logfile ""
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.