Skip to content

Borderlands 3 Hotfixes

CJ Kucera edited this page Dec 24, 2020 · 29 revisions

This page intends to document what we know about the hotfix system in use by Borderlands 3. If you're interested in tracking changes to the hotfixes that GBX provides for Borderlands 3, a github repo was set up which checks for hotfixes hourly and uploads new versions where appropriate. Feel free to check it out over here: https://github.com/BLCM/bl3hotfixes

The official GBX hotfixes have been getting uploaded to a Google Sheet, which makes analyzing some of their structure a bit more easily. This has been getting updated pretty regularly, though make sure you check the last-updated date in the document title: BL3 Hotfixes on Google Sheets.

Hotfix Keys/Operations

BL2/TPS had three different hotfix key operations: SparkPatchEntry, SparkOnDemandPatchEntry, and SparkLevelPatchEntry. These were used for globally-applicable hotfixes, package-specific hotfixes (characters and vehicles), and levels-specific hotfixes, respectively.

BL3 currently has had five hotfix operations which have been used in official hotfixes:

  • SparkPatchEntry - Globally-applicable hotfixes. Interestingly, so far all the modifications to player characters have used this kind of hotfix, which is different from how BL2/TPS would've done it.
  • SparkLevelPatchEntry - Used basically just like BL2/TPS's version, with the exception that the level name must be specified, otherwise the hotfix will do nothing. So level-based hotfixes can't be used as "globally-applied" hotfixes anymore.
  • SparkEarlyLevelPatchEntry - Presumably used just like the non-Early version, but happens earlier on in the level-loading sequence. So far this has only been used for a single hotfix setting some spawn parameters on an object.
  • SparkCharacterLoadedEntry - So far, all the GBX-provided hotfixes have used this to alter enemy data. Data like enemies seems to be loaded much more on-demand than it was in BL2/TPS, so enemy data won't necessarily exist on level-load, which is presumably why this one exists.
  • SparkSaveGameEntry - Presumably used to tweak incorrect values in savegames.

Additionally, there appear to be two other kinds of hotfix operations which have not been seen yet, so it's a bit difficult to know exactly how they would be used:

  • SparkPostLoadedEntry
  • SparkStreamedPackageEntry

Hotfix Values

The hotfixes used in BL3 are at least slightly different from the ones used in both BL2 and TPS, though the general syntax is still the same. Here's an example of a very simple hotfix:

(1,1,1,Crypt_P),/Game/Cinematics/_Design/NPCs/BPCine_Actor_Typhon.BPCine_Actor_Typhon_C:SkeletalMesh_GEN_VARIABLE,bEnableUpdateRateOptimizations,4,True,False

Two things will be obvious to folks already familiar with BL2/TPS hotfixes: the "package" field has been expanded, and there's an extra number inbetween the attribute and the "old" value. For clarity's sake, here's the fields split out:

  1. (1,1,1,Crypt_P)
  2. /Game/Cinematics/_Design/NPCs/BPCine_Actor_Typhon.BPCine_Actor_Typhon_C:SkeletalMesh_GEN_VARIABLE
  3. bEnableUpdateRateOptimizations
  4. 4
  5. True
  6. False

The extra number field (field 4 in the list above) is easy enough to explain: it's simply the string length of the "old" value. The string True has four characters, so the number is 4. This was presumably added in because that way it's easy to include old values which contain commas, without having to worry about quoting the values properly, etc. If the game knows the string length, it can just read that many bytes and then proceed to process the rest of the hotfix. To construct a hotfix which doesn't check for existing values (ie: a set rather than set_cmp, in BLCMM parlance), set the "from" length to zero and leave the next field blank, as usual.

The package field has been expanded to include quite a bit more information. I've been calling it a "package tuple".

The first of the numbers is always 1, and the game will reject a hotfix which has any other value.

The second of the numbers determines the type of hotfix, and so far we've seen a few values for that: 1, 2, 4, 6, 7, 8, and 11. This number can have a big effect on anything looking to process hotfixes, and can alter the number of fields that show up in the rest of the hotfixes. I've been calling it a "type," though that term's unlikely to be what GBX calls it. See the next section for information on that.

The third number is technically a bitfield, though only bit 0 is being checked currently, so this value will always be 0 or 1 for the moment. It's used internally to specify whether the modified object should be notified when the hotfix is applied or removed. The circumstances under which you'd want to use one or the other remains fairly opaque. In practice, 0 seems to work most of the time, though there are plenty of GBX-provided hotfixes which use 1

The fourth field in there is the "target" of the hotfix operation, and is generally only seen in SparkLevelPatchEntry, SparkEarlyLevelPatchEntry, and SparkCharacterLoadedEntry hotfixes. This is where you specify the level in which to run the hotfix, or the character whose load will trigger the hotfix. Unlike in BL2/TPS, leaving this blank does not work as a wildcard, but you can instead use the special keyword MatchAll to have a hotfix operate on all level loads, or on all character loads.

Hotfix Types

The second number in the "package" field determines the type of the hotfix, which will alter how the hotfix looks.

Hotfix Type 1: "Regular" Hotfixes - Property/Attribute in Object

This is the most familiar-looking hotfix, such as the example above. It alters the named attribuet which exists right in the object in question. The field list for this kind of hotfix is:

  1. Package Tuple
  2. Object Name
  3. Attribute Name
  4. "From" Length
  5. "From" Value
  6. "To" Value

Hotfix Type 2: DataTable Alterations

BL3 has a new data structure used in a variety of circumstances which is called a DataTable. These tables seem to have "rows" which can be referenced by name, and hotfix type 2 will let you specify which row to act on.

  1. Package Tuple
  2. Object Name
  3. Row Name
  4. Attribute Name
  5. "From" Length
  6. "From" Value
  7. "To" Value

For instance, here's one currently-active hotfix:

(1,2,0,),/Game/GameData/Modifiers/DataTable_Mayhem_CoreMods_Easy.DataTable_Mayhem_CoreMods_Easy,ExpGain_CombatOnly,MinValue,8,2.000000,0.100000
  1. Package: (1,2,0,)
  2. Object: /Game/GameData/Modifiers/DataTable_Mayhem_CoreMods_Easy.DataTable_Mayhem_CoreMods_Easy
  3. Row Name: ExpGain_CombatOnly
  4. Attribute: MinValue
  5. "From" Length: 8
  6. "From" Value: 2.000000
  7. "To" Value: 0.100000

Hotfix Type 3: CVar Alterations

No official GBX-provided hotfix has been seen which uses this yet, but this hotfix type could theoretically be used to set engine-level CVars to alter how the game does its stuff. The syntax is currently unknown.

Hotfix Type 4: Savegame MissionObjective Alteration

This type has only been seen inside SparkSaveGameEntry hotfixes so far, of which we've only seen two examples. The currently-active one looks like:

(1,4,0,),/Game/Missions/Plot/Mission_Ep02_Sacrifice.Mission_Ep02_Sacrifice_C,1,/Game/Missions/Plot/Mission_Ep02_Sacrifice.Set_WatchMouthpieceMovie_ObjectiveSet,(8,9),(1,0),(2,2)

As suggested by the MissionObjective name, this is used to alter saved mission objectives, to tweak values which might have been blocking progress or something. I haven't taken the time to try and figure out what most of those fields mean:

  1. Package
  2. Mission Object Name
  3. Unknown Number 1
  4. Objective Object Name
  5. Unknown two-digit tuple 1
  6. Unknown two-digit tuple 2 ("from" value?)
  7. Unknown two-digit tuple 3 ("to" value?)

This type is unlikely to be useful to modders anyway, of course.

Hotfix Type 5: Savegame MissionObjectiveSet Alteration

Like type 4, this has only been seen in conjunction with SparkSaveGameEntry hotfixes, so it's clearly something savegame-related, and additionally is also related to mission objectives. The currently-active one looks like:

(1,5,0,),/Game/Missions/Plot/Mission_Ep05_OvercomeHQBlockade.Mission_Ep05_OvercomeHQBlockade_C,1,/Game/Missions/Plot/Mission_Ep05_OvercomeHQBlockade.SET_ContactAtlas_RhysConversation_ObjectiveSet,53,1,/Game/Missions/Plot/Mission_Ep05_OvercomeHQBlockade.SET_TalkToLorelai_Monocycle_ObjectiveSet

I haven't taken the time to try and figure out what most of those fields mean:

  1. Package
  2. Mission Object Name
  3. Unknown Number 1
  4. ObjectiveSet Object Name
  5. Unknown Number 2
  6. Unknown Number 3
  7. Another ObjectiveSet Object Name

Hotfix Type 6: SpawnMesh Alterations

This hotfix type is used to alter some ingame mesh information, so these are altering level geometry in some ways. The values set will include a pipe-and-comma-delimited array of numbers, but I don't know exactly what's being changed in them yet. Here's one currently-active example:

(1,6,0,AtlasHQ_P),/Game/Maps/Zone_1/AtlasHQ,/Game/LevelArt/Environments/Promethea/AtlasHQ/Architecture/Pillars/Model/Meshes,SM_AtlasHQ_Pillar_V1,90,"-9392.000000,-2797.000000,928.000000|0.000000,0.000319,0.000000|1.500000,0.750000,1.500000",0
  1. Package
  2. Object Name
  3. Attribute name?
  4. Length of the next field
  5. Pipe-and-comma-delimited array of numbers
  6. A number. In all observed examples so far, it's been either 0 or 1

Hotfix Type 7: Blueprint Bytecode Alterations

This type apparently alters the bytecodes which are generated as the result of Unreal Engine Blueprint compilation. So far, the few examples we have of these have been editing some objects which are related to player character abilities (including one which relates to guardian rank). Here's an example:

(1,7,0,),/Game/PlayerCharacters/Beastmaster/_Shared/_Design/Passives/Ranged1/Passive_Beastmaster_Ranged1.Passive_Beastmaster_Ranged1_C,0,1,ExecuteUbergraph_Passive_Beastmaster_Ranged1,1,312,8:0.100000,3:2.0
  1. Package
  2. Object Name
  3. Unknown Number 1
  4. Unknown Number 2
  5. Attribute Name?
  6. Unknown Number 3
  7. Unknown Number 4 - bytecode offset, perhaps?
  8. "From" Value, prefixed with the length of the "From" string by use of a colon
  9. "To" Value, prefixed with the length of the "To" string by use of a colon

Presumably, to use this hotfix type effectively, you'd need to be able to parse the existing blueprint bytecodes to figure out what exactly to change.

Hotfix Type 8: Material Interface Alterations

This type of hotfix was first seen on the June 11, 2020 hotfix update (which added the Guardian Takedown). Its exact fields aren't known, but there aren't too many fields in there. There's an example:

(1,8,1,GuardianTakedown_P),/Game/PatchDLC/Takedown2/Maps/GuardianTakedown_Temple.GuardianTakedown_Temple:PersistentLevel.IO_CryptPillar_2.StaticMesh1,0,/GbxSharedBlockoutAssets/_Shared/Model/Materials/Grayscale/MI_GrayScale_10.MI_GrayScale_10,MI_Eridian_Wall_Atlas_V2
  1. Package
  2. Object Name
  3. Unknown Number 1
  4. Material Interface Path
  5. material Interface Name

Hotfix Type 9: Unknown

Nothing much to say about this. We don't even have a label for them, let alone examples.

Hotfix Type 10: Unknown

Nothing much to say about this. We don't even have a label for them, let alone examples.

Hotfix Type: 11: Stream Blueprint Alterations

This type was introduced with the 2019-11-21 patch, which in addition to the Maliwan Takedown added a "Hotfixes Applied" sign on the main menu, and so far the two type-11 hotfixes are related to that sign. These are pretty clearly closely related to types 6 and 7 as well, though the exact syntax hasn't really been worked out yet. Here's the first example:

(1,11,0,MenuMap_P),/Game/Maps/MenuMap,/Game/Patch/MicropatchApplied,IO_MainMenu_HotfixIndicator,80,"0.000000,0.000000,0.000000|0.000000,0.000000,0.000000|1.000000,1.000000,1.000000"
  1. Package
  2. Map reference?
  3. Variable status check?
  4. Interactive object?
  5. Unknown Number 1
  6. Pipe-and-comma-delimited array of numbers

Conclusion

That's it, so far! As more hotfixes get rolled out, some of the mysteries here could get cleared up. Some mysteries would probably be cleared up by just taking a closer look at the GBX-provided changelogs and matching them up to the downloaded hotfixes. One other thing that would probably help would be to have a good set of dumped data from the game, though BL3 makes that rather more complicated than the easier situation we had with BL2/TPS.

Clone this wiki locally