Tutorial: Hotfix Data - BLCM/BLCMods GitHub Wiki
Note: this is an old tutorial. The information may still be useful, you will probably be better served by the new one, Tutorial: Getting Started Making Mods.
It is best to understand how to use normal set commands first before diving into hotfixes. See Here
(original version of this page thanks to adudney)
Hotfixes behave exactly like set commands but delay taking effect until you enter the game. This allows for changing things such as skills and enemies, which only load once you're actually in game.
In general, if you can obj dump
something from the console at the main menu, you can use a regular set
command, but if you can't, then you'll have to use a Hotfix instead.
There are 3 types of hotfix: Patch, On Demand, and Level.
- Patch types execute right when hitting continue / new game. They work just like normal set lines, and are unnecessary to use most of the time. Generally the only time you'll see these is in official Gearbox hotfixes.
- On Demand types execute when a package is loaded (such as character skills). This is best used for skills, since you can load the skill changes when the character loads. For example,
GD_Siren_Streaming
is loaded whenever Maya is loaded. - Level types execute on changing level (such as entering Sanctuary). This is often used to make changes to enemy or boss behaviors, such as Varkid evolution chances, OOO's evolve chances, loot changes, etc. The level names to use in the hotfix can be found in the Level Name Reference page.
OpenBLCMM makes it very easy to create a hotfix: just click the "Hotfix" checkbox at the top of the code edit window. You can use the dropdown to choose whether to create a Patch, On Demand, or Level hotfix, choose the level name or package name, and optionally give the hotfix a descriptive name. The code you write continues to look just like a regular set
command that you're already familiar with.
In addition to giving you access to objects which aren't loaded by default otherwise, and providing level-and-character specific commands, hotfixes also let us do a few other things that we can't do with ordinary set
statements.
One is that we can "drill into" a data structure. For instance, if you wanted to change Gettle's drop from the Lyuda to the Pitchfork with a regular set
statement, which you'd do in GD_Itempools.Runnables.Pool_Gettle
, you'd have to set the entire BalancedItems
structure, with a statement that looks something like:
set GD_Itempools.Runnables.Pool_Gettle BalancedItems
(
(
ItmPoolDefinition=None,
InvBalanceDefinition=WeaponBalanceDefinition'GD_Weap_SniperRifles.A_Weapons_Legendary.Sniper_Dahl_5_Pitchfork',
Probability=(
BaseValueConstant=0.000000,
BaseValueAttribute=None,
InitializationDefinition=AttributeInitializationDefinition'GD_Balance.Weighting.Weight_1_Common',
BaseValueScaleConstant=1.000000
),
bDropOnDeath=True
)
)
Whereas if you used a hotfix, you'd be able to do a statement like this:
set GD_Itempools.Runnables.Pool_Gettle BalancedItems[0].InvBalanceDefinition WeaponBalanceDefinition'GD_Weap_SniperRifles.A_Weapons_Legendary.Sniper_Dahl_5_Pitchfork'
Much more concise!
The other thing that hotfixes can do is set themselves to only execute if the attribute being changed is already equal to a known value. This is basically never used in community-created mods, but Gearbox uses this in some of their official hotfixes, and there's nothing preventing mod authors from doing it as well. For instance, one of the default Gearbox hotfixes in BL2 is:
set_cmp GD_Balance.WeightingPlayerCount.BugmorphCocoon_PerPlayers_Phase1 ConditionalInitialization.ConditionalExpressionList[4].BaseValueIfTrue.BaseValueConstant 0.7 0.8
So that particular phase of Varkid evolution will be changed to 0.8
, but only if it was 0.7
to begin with. If some other statement has already changed the evolution change before that hotfix has a chance to execute, the hotfix won't actually do anything.
The Pre-Sequel added an interesting feature to hotfixes where you can add to an existing array without having to redefine the whole thing. For instance, one of the default Gearbox TPS hotfixes looks like this (edited a bit for length):
set GD_Population_Scavengers.Balance.Outlaws.PawnBalance_ScavWastelandWalker PlayThroughs[0].CustomItemPoolList +(ItemPool=GD_Itempools.Runnables.Pool_ScavBadassSpacemanMidget,...)
Which adds the pool GD_Itempools.Runnables.Pool_ScavBadassSpacemanMidget
to Swagman's drop pool. Unfortunately, this syntax is not available in BL2.
FilterTool already abstracted hotfixes so that you don't need to know what they actually look like in the file, and OpenBLCMM takes it further. When constructing hotfixes in OpenBLCMM, you just write set
statements like you're used to doing, just with an extra checkbox selected at the top of the window. So, keep in mind that you should never have to actually know any of the information in this section.
If you ever do look into the actual files themselves, though, hotfixes are structured as such:
Patch:
"<object>,<path>,<old_value>,<value>"
On Demand:
"<package>,<object>,<path>,<old_value>,<value>"
Level:
"<level>,<object>,<path>,<old_value>,<value>"
Note that level
, package
, and old_value
can be empty.
Additionally, each hotfix has a name associated with it. If you look at the bottom of a patch file with hotfixes, you'll see two set statements:
set Transient.SparkServiceConfiguration_6 Keys ("SparkLevelPatchEntry-GBX_fixes1",...)
set Transient.SparkServiceConfiguration_6 Values (",GD_Balance.WeightingPlayerCount...",...)
So the names go into Keys
and the hotfixes themselves go into Values
.